Introduction change
With this final assignment both an open water model and a groundwater
model will be developed which will be coupled.
De open water model represents a small river called the Hooge Raam. The
groundwater model will simulate the transition of precipitation into
drainage and surface runoff of the area surrounding the Hooge
Raam.
Flow in the open water model is based on the diffusive wave (“Froude =
0”) approximation in 1D. Groundwater flow is based on Darcy’s equation
and simulates the flow between two open water courses (ditches or
drains) in 1D. Groundwater flow will be simulated in transient mode to
account for storage changes. The open water flow model simulates in
pseudo stationary mode.
A storm event, a heavy rain shower, is the forcing for which we will
investigate flow from the surface into the soil, towards ditches and
finally to the Hooge Raam to get discharged at the weir on the lower
side.
The Hooge Raam is located just below the small town Grave and is part
of the water board “Aa en Maas”. The surrounding area is mainly used as
grasslands, some cornfields and a few forest plots. The area is
reasonably flat where surface levels range from 15.5 till about 17.5 m
AMSL (Above Mean Sea Level).
The figure below gives an overview of the Hooge Raam which will be
considered for modeling.
Overview Hooge Raam and area
The first part contains the explanation and assignments for the open
water model, the second will go into the details of the groundwater
model, the coupling of both models is described in the third part and
finally the last part (4) contains the setup to determine derived
uncertainties of the “model-train”.
PART 1 the Open water model
Open water equations
This document should give an introduction to the hydraulic modeling
of the Hooge Raam river.
An attempt is made to make the document self contained. For that
reason we start by giving some basic formulas, and more formulas will
follow further in the document. This document should however not to be
considered as a course in hydrodynamics. The formulas are cited (which
should be for most of you a repetition?) to form the base of the
code.
The flow in rivers as the Hooge Raam is most often described by the
so called St-Venant equations, expressing respectively the mass and the
momentum balance (only in x-direction:
\[
\frac{\partial A}{\partial t} + \frac{\partial Q}{\partial x} = I\\
\frac{\partial Q}{\partial t} + \frac{\partial Q\,u}{\partial x}
= g\;A\;\Big( S_o - S_f - \frac{\partial a}{\partial x}\Big)
\]
As we are here less interested in highly dynamic open water
calculations, a simplification of the second equation above will be
used. This simplification starts from the observation that in many
situations (certainly lowland situations) the first two terms in the
momentum part of the St-Venant equations are much smaller than the terms
on the right hand side.
\[
\frac{\partial Q}{\partial t} + \frac{\partial Q\,u}{\partial x} =
g\;A\;\Big( S_o - S_f - \frac{\partial a}{\partial x}\Big)\\
\Downarrow \\
0 = g\;A\;\Big( S_o - S_f - \frac{\partial a}{\partial x}\Big)\\
\Downarrow \\
0 = S_o - S_f - \frac{\partial a}{\partial x}
\]
The meaning of the terms in these equations will be explained when
they first appear in this document.
In these exercises situations will be studied where
- the flow in the Hooge Raam can be considered to be
stationary (so the time derivatives in the equations above
disappear)
- there is a weir at the downstream end of the river
Situations of this type are often called backwater
curves.
This type of open water model that will be developed in this document
will be coupled with a groundwater model. So at some places typical
groundwater terms and dimensions may occur.
The open water has its own standard units:
- length unit = \(m\) meter
- time unit = \(s\) second
Hooge Raam dimensions and parameters
We are going to simulate the open water flow of the Hooge Raam
starting at the southern part at the “Vliesweg” with a prescribed flux
coming from the discharging upstream area. At the northern part of the
Hooge Raam section it discharges through a weir, which finally is
getting discharged into the Meuse.
We will use the following data for dimensioning the river. Data is
based on “legger” waterboard Aa en Maas.
You may want to quickly browse through this “legger” to see what
information is available. Go to https://www.aaenmaas.nl/onswerk/regels/legger/ and open
the ‘Legger oppervlaktewater’.
The length of this reach of the Hooge Raam is 1470 m. Upstream bottom
level 14.50 m AMSL, downstream bottom level 11.80 m AMSL, (average)
bottom width 2.10 m, (average) side slope 1.5 m/m.
Weir: crest width 2.0 m, crest height: 11.45 and 12.60 m.
Influx stationary upstream based on base flow as discharge of an
upstream area of 250 ha (assume a discharge of 0.5 l/s/ha).
rm(list = ls())
HR.Qin = 250*0.005 #250ha * 0.5 l/s/ha
cat('Total influx upstream : ',HR.Qin)
Total influx upstream : 1.25
Longitudinal view
It is conventional to measure the length along the river from
upstream to downstream. The domain of the river starts at 0 m.
We will also need the bottom slope in what follows. In the equations
of the introduction this slope was called \(S_o\). It is defined as the drop of bottom
level per unit length of the river. Here it is just a constant:
HR.length = 1470
HR.domain = c(0,HR.length)
HR.botelev.upstream = 14.50
HR.botelev.downstream = 11.80
HR.So = (HR.botelev.upstream -HR.botelev.downstream)/(HR.length) #% botelev.upstream #% botelev.dnstream #% length
cat('So = ',HR.So)
So = 0.001836735
HR.zb = approxfun(HR.domain,c(HR.botelev.upstream,HR.botelev.downstream),
rule=2)
plot(HR.domain,HR.zb(HR.domain),type = "l",col="brown",lwd=4,
main="Hooge Raam bed bottom",xlab="x (m)", ylab= "z (m)")
grid()

This bottom slope brings the gravity into the equations: the higher
this slope, the larger the influence of the gravity on the water
flow.
Cross section geometry
The cross section can in general have a complex and spatially varying
form. Her we take just a simple trapezoidal profile with a constant
bottom width \(b\) and constant side
slope \(m\):
HR.b=2.1 # bottom width
HR.m=1.5 # side slope
The water level with respect to the bottom of this cross section is
called the water depth and will be denoted by \(a\). To make a plot of the cross section we
need to calculate the width for a whole range of possible water
depths.
For a trapezoidal cross section this results in:
HR.width = function(a)
{
return(HR.b+2*HR.m*a)
}
The next chunk creates a plot of the cross section
arange=seq(0,1.5,length=100) # large enough of possible depth values
widthrange = HR.width(arange)
plot(c(-rev(widthrange/2),widthrange/2),c(rev(arange),arange),
xlab="y",ylab="a",main="cross section",type="l",lwd=5,col="brown")
grid(col="black")

Wetted area
One of the important cross section functions is the wetted area. It
was in the St-Venant equation denoted by \(A\). For a trapezoidal cross section this
can be easily calculated by the following function:
HR.A = function(a)
{
return(HR.b*a+HR.m*a^2)
}
One of the reasons that this wetted cross section is so important is
because of the important formula \(Q = v
A\), were \(Q\) is the
discharge, \(v\) is the velocity and
\(A\) is the wetted cross section. Some
typical (max) velocities depending of the soil type are given the table
below
source: Cultuurtechnisch Vademecum 1988
| clay/loam/loess |
0.60 - 0.80 |
| sand/solid peat |
0.30 - 0.60 |
| coarse sand |
0.20 - 0.50 |
| fine sand/soft peat |
0.15 - 0.30 |
As can be seen in the function above that the wetted cross section is
dependent on the water depth \(a\). One
way to see the influence of the wetted cross section on the discharge is
to investigate the relationship between \(Q\) and \(a\) for fixed velocities. Here is a typical
example (it is customary to plot water depths on the vertical axis):
Arange = HR.A(arange)
vel = 0.50 #m/s velocity for coarse sand
Qrange = vel*Arange
plot(Qrange,arange,
main="Hooge Raam Q-a relation for fixed velocity v",
xlab="Q (m^3/s)",ylab="a (m)",col="brown",lwd=3,type="l")
legend("bottomright", inset=.05, title="v (m/s)",
c("0.5"), col=c("brown"),lwd=3,horiz=TRUE)
grid(col="black")

Velocities higher than 1 m/s are however rather atypical.
Fill the chunk below (replace all XXX) with a code that combines in
one
plot the a-Q for four realistic velocities.
Arange = HR.A(arange) #Calculating wetted area
Q1range = 0.15*Arange #Clay/loam/loess velocity
Q2range= 0.20*Arange #Sand/solid peat velocity
Q3range= 0.30*Arange #Coarse sand
Q4range = 0.60*Arange #Fine sand/soft peat
plot(Q4range,arange, #Make a plot of fine sand
main="Hooge Raam Q-a relation for fixed velocity v", #Title
xlab=expression(Q~(m^3/s)),ylab="a (m)",col="brown",lwd=3,type="l", ylim=c(0,1.5), xlim = c(0,2)) #Settings for plot
lines(Q3range,arange,lwd=3,col="blue") #Adding plot of coarse sand
lines(Q2range,arange,lwd=3,col="red") #Adding plot of sand/solid peat
lines(Q1range,arange,lwd=3,col="green") #Adding plot of clay/loam/loess
legend("bottomright", inset=c(0.001), title="v (m/s)", #Adding the legend
c("clay, 0.15","sand, 0.20","coarse sand, 0.30","fine sand, 0.60"), col=c("green","red","blue","brown"),lwd=3,horiz=TRUE, cex = 0.6) #Color the difference scenario
grid(col="black") #Making the color of the grid to be black

NA
NA
Equilibrium discharge
But of course usually both and \(A\)
and \(v\) change if the water depth
\(a\) changes.
For equilibrium situations this relationship can be investigated
through formulas. Equilibrium means that the water depth is constant in
space (\(\frac{\partial a}{\partial x} =
0\)) in terms of the St-Venant equations of the introduction) and
time. For this situation the open water equation simplifies into; \[S_0 = S_f = \frac{n^2\; Q^2}{A^2\;
R^{4/3}}\]
From this one can derive: \[Q_\mathrm{equi} = \frac{\sqrt{S_o}}{n} A\;
R^{2/3}\] where
\(S_o\): bottom slope (as
calculated above)
\(n\): Manning coefficient: the
higher this number, the more friction, typical values are around 0.04,
but difficult to assess
\(A\): the wetted cross section,
as discussed and calculated above
\(R\): hydraulic radius.
Formally defined as wetted Area divided by the wetted perimeter(\(R=\frac {A}{P}\)), as in the next
chunk:
HR.n = 0.045
HR.R = function(a)
{
return((HR.b*a+HR.m*a^2)/(HR.b+2*sqrt(1+HR.m^2)*a))
}
HR.Qequi = function(a)
{
R = HR.R(a)
A = HR.A(a)
Q = sqrt(HR.So)/HR.n*A*R^(2/3) #% =
return(sqrt(HR.So)/HR.n*A*R^(2/3))
}
Qequirange = HR.Qequi(arange)
plot(Qequirange,arange,
main="Hooge Raam Q-a equilibrium",
xlab="Qequi",ylab="a",lwd=3,col="blue",type="l")
grid(col="black")

Sometimes the question is posed the other way around. Assume that one
wants to drain a constant intensity of 10 \(mm/day\) of an area of the size of 30 \(km^2\) through this river.
Step1: calculate the discharge through the river.
area = 30 # km^2
area = area *(1000)^2 # m^2
I = 10 # mm /day
I = I/(1000*24*3600) # m/s #+ =
Q = I*area
Now we want to calculate the water level corresponding to the
equilibrium discharge just calculated. We can use the plot made above,
or we can use the following chunk to find the water level corresponding
to the calculated discharge rate.
#install.packages("nleqslv")
library(nleqslv)
Warning: package ‘nleqslv’ was built under R version 4.3.2
tosolve = function(a){return (HR.Qequi(a)-Q)}
aequi = nleqslv(1,tosolve)$x
print(aequi)
[1] 1.177077
Repeat the calculation above for the rainfall intensities between 0.5
mm/day and 15 mm/day and make a plot of the water depths vs these
intensities.
Is = seq(0.5,15,length=100)
aequis = c()
for( i in 1:length(Is))
{
I = Is[i]/(3600*24*1000)
Q = I*area
tosolve = function(a){return (HR.Qequi(a)-Q)}
aequis[i] = nleqslv(1,tosolve)$x
}
plot(Is,aequis,type="l",col="blue",lwd=3, main="Water Depth for Different Rain Intensities", xlab = "Rainfall intensity (mm/day)", ylab = "Steady state water level (m)")
grid(col="black")

The downstream weir
Geometry of the weir
See the following graph
HR.weir.width = 2.25 #m width of the weir floor
HR.weir.crest = 1 #m above bottom river
# draw weir in cross section
plot(c(-rev(widthrange/2),widthrange/2),c(rev(arange),arange),
xlab="y",ylab="a",main="cross section",type="l",lwd=5,col="brown")
lines(c(-HR.weir.width/2,-HR.weir.width/2,HR.weir.width/2,HR.weir.width/2),
c(max(arange),HR.weir.crest,HR.weir.crest,max(arange))
,col="blue",lwd=3)
legend("bottomright", inset=.05,
c("river","weir"), col=c("brown","blue"),lwd=3,horiz=FALSE)
grid(col="black")

Weir Q-a relation
The amount of water flowing over a weir is a function of the water
height above the crest. For a rectangular weir this is a well known
formula: \[Q_\mathrm{weir} = 1.83\;
B_\mathrm{weir}\; (a-c_\mathrm{weir})^{3/2}\]
Finish the code below such that the function calculates discharges
according to the formula above.
HR.weirQ = function(a)
{
a[a<HR.weir.crest] = HR.weir.crest
return(1.83*HR.weir.width*(a-HR.weir.crest)^(3/2))
}
weirQrange = HR.weirQ(arange)
## MAKE THE PLOT NICER BY ADJUSTING XLIM YLIM AND LEGEND
plot(Qequirange,arange,main="Qequi (without weir) and Qweir for HoogeRaam",
xlab="Qequi",ylab="a",lwd=3,col="blue",type="l", ylim = c(0,1.5))
lines(weirQrange,arange,lwd=3,col="red")
legend("bottomright", inset=.05,
c("Qequiriver","Qweir"), col=c("blue","red"),lwd=3,horiz=FALSE)
grid(col="black")

Rough backwater approximation
For any given fixed discharge \(Q\)
that goes through the Hooge Raam, we can calculate two water levels with
the information above:
In between the water levels will vary between these two. Here we
first are going to calculate these levels and then just as a first rough
approximation interpolate linear in between.
Calculate for Q=1.2 the water depth at the weir and the water depth
at the upstream end
library(nleqslv)
Q = 1.2
#Water level far upstream
tosolve = function(a){return (HR.Qequi(a)-Q)}
aequi = nleqslv(1,tosolve)$x
print(aequi)
[1] 0.675549
#Water level at the weir
tosolve = function(a){return (HR.weirQ(a)-Q)}
aweir = nleqslv(1.1,tosolve)$x
print(aweir)
[1] 1.439574
Make a function for the rough linear approximation and plot it
HR.bwrough = approxfun(HR.domain,
c(HR.botelev.upstream+aequi,HR.botelev.downstream+aweir),rule=2) #% aequi #% aweir
plot(HR.domain,HR.bwrough(HR.domain),ylim=c(HR.botelev.downstream,HR.botelev.upstream+aequi),
main=paste("rough level approx for Q=",Q),
xlab="l (m)",ylab="h (m)",col="blue",lwd=4,type="l")
lines(HR.domain,HR.zb(HR.domain),col="brown",lwd=4)

#Add legend, blue is water elevation and brown is river bed elevation
Setup of base backwater model
The previous backwater approximation is too rough. In reality the
water levels will vary non-linear (but still very smoothly). A 1D flow
model has to be setup to calculate these levels. So the 1D flow library
needs to be loaded:
library(FVFE1D)
Loading required package: Matrix
The choice of state
For all kind of local calculations the water depth \(a\) is the most common choice. For
non-local problems as the calculation of a backwater curve, the
water level with respect to AMSL (the \(h\) in the plot above) is the most common
choice. These two quantities are connected through the river, bottom
height:
\[
h = z_b(x)+a
\]
For the Hooge Raam, a function for the bottom was already given:
HR.zb (see above).
The equation
Finish the function definition below:
HR.a = function(x,h)
{
return(h-HR.zb(x)) #
}
The internal flux function
The theory
The most important step in defining a flow model is the definition of
the internal flux. The definition follows from the equation as given at
the start of this document:
\[
0 = S_o - S_f - \frac{\partial a}{\partial x}
\]
The formula for the friction slope, \(S_f\), requires now a bit more
sophistication.
The flow can now be to the right (\(Q>0\)) or to the left (\(Q<0\)). Although in the given situation
and with the current choice of domain, the flow should be to the right
and thus positive, it can not be excluded that during the numerical
calculations it may be (locally) different. The friction slope is
technically defined as the amount of energy loss if going in the
positive x-direction.
- if the flow is in the positive x-direction (\(Q>0\)), their should be loss in the
positive x-direction, so the friction slope should be positive
- if the flow is in the negative x-direction (\(Q<0\)), their should be loss in the
negative x-direction, so the friction slope should be negative
These two cases can be combined into one formula:
\[
S_f = \mathrm{sign}(Q) \frac{n^2\; Q^2}{A^2\; R^{4/3}}
\]
where the sign function is defined as in the R-language.
Use the help of R to give a definition of the sign function
below:
Using this result, the simplified St-Venant can be written as:
\[
\mathrm{sign}(Q) \;
\frac{n^2\; Q^2}{A^2\; R^{4/3}} = S_f = S_o - \frac{\partial a}{\partial
x} =
-\frac{\partial z_b}{\partial x} - \frac{\partial a}{\partial x} =
-\frac{\partial h}{\partial x}
\]
Rewriting this gives: \[Q =
-\frac{1}{n}\; \mathrm{sign}\Big(\frac{\partial h}{\partial x}\Big)\;
\sqrt{ \Big| \frac{\partial h}{\partial x} \Big|}\; A\;
R^{2/3}\]
As you can see, the choice of \(h\)
as state is convenient here.
The code
HR.Q= function(x,state,gradstate)
{
a = HR.a(x,state)
R = HR.R(a)
A = HR.A(a)
return(-1/HR.n*sign(gradstate)*sqrt(abs(gradstate))*A*R^(2/3)) #+ (
}
Model 1: the Hooge Raam base model
HR.backwatermodel = newFLOW1D(domain=HR.domain,systemfluxfunction = HR.Q,
name = 'Hooge Raam backwater')
HR.weir.BC = function(state)
{
return(-HR.weirQ(HR.a(HR.length,state)))
}
HR.Qin = 1.2
set.BC.fluxstate(HR.backwatermodel,"right",HR.weir.BC)
set.BC.fixedflux(HR.backwatermodel,where="left","HR.Qin")
set.discretisation(HR.backwatermodel,nodes=seq(0,HR.length,length=50),method='FE')
do.initialize(HR.backwatermodel,HR.bwrough)
HR.abovebottom = function(x,state)
{
return(HR.a(x,state)>0.1)
}
set.isacceptable(HR.backwatermodel,HR.abovebottom)
Discuss:
- The minus sign in the definition of the lower boundary
condition:
- use the help of FVFE1D to discuss the role of the double quotes
around HR.Qin in the definition of the upstream boundary condition:
- describe the acceptability condition of the model for the level in
words:
solve.steps(HR.backwatermodel)
$RMSM
[1] 1.7876e-06
$MAM
[1] 1.109677e-05
plot(HR.backwatermodel,fluxplot=TRUE)

And a nice plot to compare the rough (linear) approximation with the
smooth one:
plot(HR.domain,HR.bwrough(HR.domain),ylim=c(HR.botelev.downstream,HR.botelev.upstream+aequi),
main=paste("Backwater curve for Q=",HR.Qin),
xlab="l (m)",ylab="h (m)",col="green",lty=2,lwd=4,type="l")
lines(HR.domain,HR.zb(HR.domain),col="brown",lwd=4)
HR.states.1 = dataframe.states(HR.backwatermodel)
lines(HR.states.1,col="blue",lwd=4)
legend("bottomleft", inset=.05,
c("bottom","raw backwater","true backwater"),
col=c("brown","green","blue"),lty=c(1,2,1),
lwd=3,horiz=FALSE)

Model 2: adding drainage
All the approaches only considered the Hooge Raam as a transport
river: water coming in upstream had to be transported downstream. In
reality input (in draining situations) of water does also occur along
the trajectory. This is called lateral inflow. In terms of the
FVFE1D package this is called spatialflux. In this example we
will think of this flux coming from draining the arabel land where water
collected in ditches and drain tubes ending up in the river. We will
think of this drainage flux to be uniform over the length of the river.
In this case this is called HR.lateraldrainage. The name lateral is a
typical name for this type of fluxes in open water: lateral means
“coming from the side”, so external.
A proper value for this number should come from a groundwater model.
For an example value here we just take 50% of the inflow upstream as a
total, that has to be distributed over the length of the river.
HR.lateraldrainage = 0.5*HR.Qin/HR.length
add.spatialflux(HR.backwatermodel,rate="HR.lateraldrainage",name="drainage")
solve.steps(HR.backwatermodel,verboselevel = 1)
[1] "iteration 1 ; RMSM= 0.00672594829107919 ; MAM= 0.0412489298613663"
[1] "iteration 2 ; RMSM= 0.000344874286476815 ; MAM= 0.00217852212373981"
[1] "stopped because of small RMSM= 1.38878982277522e-06"
$RMSM
[1] 1.38879e-06
$MAM
[1] 8.655063e-06
HR.states.2 = dataframe.states(HR.backwatermodel)
nodes = HR.states.2$x
plot(nodes,HR.zb(nodes),col="brown",type="l",lwd=4,ylim=c(9,16),
xlab="l",ylab="h",main=paste("backwater + lateral flow Hooge Raam"))
lines(HR.states.1,col="orange",lwd=3)
lines(HR.states.2,col="blue",lwd=3)
grid(col="black")
legend("bottomleft", inset=.05,
legend=c("without drainage","with drainage"), col=c("orange","blue"),
lwd=3,horiz=FALSE)

This concludes the first part and results in the basic open water
model simulating flow in the Hooge Raam. For the lateral inflow due to
drainage in the surrounding area of the Hooge Raam we chose an arbitrary
value. Starting from the next part (2), we will calculated this drainage
and also will determine the surface runoff when applicable.
PART 2 The groundwater model
We will assume a 1D groundwater model simulating one specific parcel,
enclosed between two ditches or drains, within the drainage area of this
part of the Hooge Raam.
This model will calculate a head distribution between both ditches. The
model determines how much drainage from the groundwater and discharge
from surface runoff (during storm events) will be allocated to the Hooge
Raam. This model must be imagined to be perpendicular to the Hooge Raam
open water model. Multiplying this length of this model (distance
between the two ditches) with a representative ‘width’ to come to the
total discharged area.
Basic groundwater equation
Since we will assume a one dimensional model and only horizontal flow
(Dupuit) the basic flow equation is:
\[
Q_{gw} = -kD_{gw} * \frac {\partial H}{\partial x}
\]
Runoff Cauchy type top boundary condition
\[
Q_{runoff}= \frac{H - H_{surface}}{C_{surface}}
\]
Dimensions and parameters groundwater model
The average ditch distance is 125 m and the transmissivity in this
area is estimated on 28 \(m^2/d\) based
on the hydraulic conductivity of the soil and the thickness.
The average ditch level is given as the average river bottom level +
20 \(cm\).
The entrance resistance, due to sediments at the bottom of the ditch,
is 3 \(days\).
When surface runoff occurs, the state exceeds the surface level of
16.0 \(m\) AMSL, a vertical resistance
of the upper soil of 20 days (Veranderingsrapportage LHM 3.30 2017, pg
23) can be assumed.
The stationary situation is based on the average yearly recharge;
about 0.8 \(mm/d\). For the transient
model a situation of a storm event with a maximum precipitation rate of
36 \(mm/hour\) during one hour, will be
used as forcing.
Transient simulations
The water balance for the transient groundwater model can be given
as:
\[
Q_{storage}= Q_{internal} + Q_{external}\\
S \frac{\partial H}{\partial t} = \frac {\partial}{\partial x}\left (
-kD \frac{\partial H}{\partial x} \right ) + \sum Q_i
\]
The Internal and External fluxes are already implemented and now we
are going to include the transient part, see also the second assignment
with FVFE in week two.
The storage coefficient is estimated on 5%. For the storm events, the
time step is set to 1 hour and the total simulation time is 10 days,
starting with a stationary situation, followed by a storm event of a
gradually increasing precipitation rate till 36 mm/hour and gradually
decreasing again during 24 hours.
A time loop is required for this simulation stepping through the
hourly time steps.
Also the previous state (head) is required and need to be stored
temporarily to determine the storage change. Tip: use
the ‘specific’ function in the FVFE1D package for for this.
Storage function
A new “external” flux for the storage now need to be defined;
Since the time derivative is \(\frac{\partial H}{\partial t} \approx \frac
{H^{t+\Delta t}-H^t}{\Delta t}\) water is stored, and not
available for internal flow, when the new head is higher than the
previous head.
Finish the Q.sto function (replace XXXX, YYYY)
old.state = state.fun(model = GW.stat) #a FUNCTION (!) to save the previous state of the model, so H at t= t to calculate the new H at t = t + delt.t .
GW.S = 0.05
Q.sto = function(x,state)
{
Storage.flux = - GW.S * (state - old.state(x))/delt.t
return(Storage.flux)
}
Transient model
The transient model is the same as the stationary model with the
addition of the storage flux.
GW.trans = copy.model(GW.stat)
add.spatialflux(model = GW.trans,rate = Q.sto,name = "storage")
summary(GW.trans)
one dimensional flow model
name: groundwater model
model has 3 spatial flux, with name
surface_runoff storage precipitation
model has no point fluxes
left BC is of type state-flux
right BC is of type state-flux
numerical model of type FElinear1D
number of nodes is 40
Storm event
The storm event is simulated within one day (24 hours) with a max of
360 mm/d during one hour half way this day.
P.pattern.rate = c(0.0008,0.015*24*(sin(pi*rep(1/24*(1:24)))),0.0008)
P.pattern.date = c(0,rep(1/24*(1:24)),(1+1/24))
P.pattern = approxfun(P.pattern.date,P.pattern.rate,rule = 2)
plot(P.pattern.date,P.pattern(P.pattern.date),type="l",col = "blue",
lwd = 2, xlab = "days",ylab = "intinsity in m/d",main = "Storm event in one day")
grid()

Time loop
Finish the time loop replacing XXXX, YYYY, ZZZZ and AAAA.
#data containers for results
GW.Q.trans = c()
GW.H.trans = c()
#using the stationary head of the stationary model for the initial head for the first time step for the transient model
old.state = state.fun(GW.trans) # first initial old state to be used in the while loop.
#time aspects
delt.t = 1/24 # 1 hour
start.time = 0
end.time = 10.0 #days
current.time = start.time
#time loop
while (current.time < end.time)
{
current.time = current.time + delt.t
P = P.pattern(current.time) #precipitatin during the storm
solve.steps(GW.trans)
#save intermediate data
wb = dataframe.balance(GW.trans)
GW.Q.trans = rbind(GW.Q.trans, c(current.time,wb[2,3],wb[3,2],wb[3,3],wb[4,2],wb[5,3]))
GW.H.trans = rbind(GW.H.trans, dataframe.states(GW.trans)[,2])
#save current state being the old state for the next time step
old.state = state.fun(GW.trans)
}
The term storage_2flow stands for storage which is
released to flow and storage_2storage is the amount of
water which will be stored.
PART 3 Coupling open water and groundwater
A “loose” coupling will be applied and analyzed. With this the open
water model will receive drainage and surface runoff fluxes from the
groundwater model.
Later on, one may use the calculated open water level to adjust the
drain depth in the groundwater model achieving a full coupling. This
will result in a full coupling: exchanging fluxes from groundwater to
open water and drain depth from open water to groundwater
Scaling of Drainage and surface runoff
The pre-calculated drainage and surface runoff of the groundwater
model are used as input (“forcing”) for the open water model
HR.backwatermodel and need to be “scaled” to proper
dimensions; \(m^3/s\).
The groundwater drainage and surface runoff fluxes are based on one
typical parcel having an average ditch distance of 125 m. There are many
of these parcels in the catchment area of the Hooge Raam. These
discharge rates have unit \(m^2/d\) and
need to be transformed to the total discharging area of the Hooge Raam
into units of \(m^3/s\). For this, you
can imagine all parcels, with an average ditch distance of 125m, were
set behind each other resulting in a, let’s call it a diffuse
length calculated as: \(\frac
{\text{total_drained_area}}{\text{ditch_distance}}\). The figure
below illustrates the determination of the total diffuse length = \({\sum\text{LocalPathLength}}=\frac{\text{Drained
Area}}{\text{Ditch Distance}}\)

Finally the groundwater drainage and surface runoff need to be
transformed to a lateral inflow rate of \(m^3/s/m_{HRcourse}\) for the Hooge
Raam.
The total considered discharging area of the Hooge Raam is 500 ha.
Determine the properly scaled drainage and runoff for the Hooge Raam
model ; HR.backwatermodel.
## from groundwater discharge to lateral inflow into the Hooge Raam open water model
HR.discharge.area = 500 * 10^4#in m2
day2sec = 86400 #from day to seconds
m2.day.to.m3.day = HR.discharge.area/L #from m2/day to m3/day; a "diffuse length" based on the total drained area divided by the L(ditch distance); unit is m because it is used to conver m2/day to m3/day
Q.drainage.m3.d = GW.Q.trans$boundary * m2.day.to.m3.day # Total drainage in the catchment
Q.drainage.m3.s = Q.drainage.m3.d/day2sec# Total drainage in the catchment
Q.drainage.m2.s = Q.drainage.m3.s/HR.length
#Drainage per m river
Q.runoff.m3.d = GW.Q.trans$surface_runoff * m2.day.to.m3.day # Total runoff in the catchment
Q.runoff.m3.s = Q.runoff.m3.d/day2sec # Total runoff in the catchment
Q.runoff.m2.s = Q.runoff.m3.s/HR.length # Runoff per m river
Closely inspect the following chunk running the open water model
HR.backwatermodel with drainage and surface fluxes coming
from the groundwater model.
####preparing open water model for drainage and surface runoff
summary(HR.backwatermodel)
plot(HR.backwatermodel,fluxplot = T)
##removing the old lateral flux and adding the new drainage and runoff lateral fluxes
rem.spatialflux(HR.backwatermodel,name = "drainage")
add.spatialflux(HR.backwatermodel,rate = "drainage",name = "drainage")
add.spatialflux(HR.backwatermodel,rate = "runoff", name = "runoff")
summary(HR.backwatermodel)
#data containers for results
HR.Q.trans = c()
HR.h.trans = c()
HR.Q_upstream = c()
HR.Q_downstream = c()
#data container for results
#plot facility
plot(nodes,HR.zb(nodes),col="brown",type="l",lwd=4,ylim=c(11,18),
xlab="l",ylab="h",main=paste("Transient water levels Hooge Raam"))
lines(dataframe.states(HR.backwatermodel), col = "blue", lwd = 3)
grid()
#delt.t = 1/24 comes from groundwater model
current.time = 0.0
#end.time = 2 comes from groundwater model
time.step = 0
####time loop for HR.backwatermodel with fluxes from the groundwater model
while(current.time < end.time)
{
current.time = current.time + delt.t
time.step = time.step + 1
drainage = Q.drainage.m2.s[time.step]
runoff = Q.runoff.m2.s[time.step]
solve.steps(HR.backwatermodel)
##saving intermediate results
wb = dataframe.balance(HR.backwatermodel)
HR.Q.trans = rbind(HR.Q.trans, c(current.time,wb[4,2],wb[3,2],wb[2,2],wb[4,3]))
HR.h.trans = rbind(HR.h.trans, dataframe.states(HR.backwatermodel)[,2])
#create plot to generate an animation in the knitted HTML document
plot(nodes,HR.zb(nodes),col="brown",type="l",lwd=4,ylim=c(11,18),
xlab="l",ylab="h",main=paste("Transient water levels Hooge Raam"))
lines(dataframe.states(HR.backwatermodel), col = "blue", lwd = 3)
grid()
}
## creating data frames for the result of the open water model with drainage and surface runoff
HR.Q.trans = data.frame(HR.Q.trans)
colnames(HR.Q.trans) = c("time","boundary_upstream","runoff","drainage","boundary_downstream")
HR.h.trans = data.frame(HR.h.trans)
Checking fluxes and total volumes
For both the transient groundwater and the pseudo-stationary open
water model the total volumes of water (in \(m^3\)) during the simulation time are
compared with both models.
groundwater
Volume balance for the groundwater model \[
Total_{in} = \sum_{t= 0}^{t=T}Precip(t)\Delta t\\
Total_{out} = \left \{ \sum_{t=0}^{t=T} Qsto(t)+\sum_{t=0}^{t=T}
Runoff(t) + \sum_{t=0}^{t=T} Drainage(t) \right \} \Delta t
\] Recall that the water balance of the groundwater model is
expressed in \(m^2/d\). To come to
volumes (\(m^3\)) one need to consider
the “diffuse length” and the time step.
####preparing open water model for drainage and surface runoff
summary(HR.backwatermodel)
one dimensional flow model
name: Hooge Raam backwater
model has 1 spatial flux, with name
drainage
model has no point fluxes
left BC is of type given flux
right BC is of type state-flux
numerical model of type FElinear1D
number of nodes is 50
plot(HR.backwatermodel,fluxplot = T)

##removing the old lateral flux and adding the new drainage and runoff lateral fluxes
rem.spatialflux(HR.backwatermodel,name = "drainage")
add.spatialflux(HR.backwatermodel,rate = "drainage",name = "drainage")
add.spatialflux(HR.backwatermodel,rate = "runoff", name = "runoff")
summary(HR.backwatermodel)
one dimensional flow model
name: Hooge Raam backwater
model has 2 spatial flux, with name
drainage runoff
model has no point fluxes
left BC is of type given flux
right BC is of type state-flux
numerical model of type FElinear1D
number of nodes is 50
#data containers for results
HR.Q.trans = c()
HR.h.trans = c()
HR.Q_upstream = c()
HR.Q_downstream = c()
#data container for results
#plot facility
plot(nodes,HR.zb(nodes),col="brown",type="l",lwd=4,ylim=c(11,18),
xlab="l",ylab="h",main=paste("Transient water levels Hooge Raam"))
lines(dataframe.states(HR.backwatermodel), col = "blue", lwd = 3)
grid()

#delt.t = 1/24 comes from groundwater model
current.time = 0.0
#end.time = 2 comes from groundwater model
time.step = 0
####time loop for HR.backwatermodel with fluxes from the groundwater model
while(current.time < end.time)
{
current.time = current.time + delt.t
time.step = time.step + 1
drainage = Q.drainage.m2.s[time.step]
runoff = Q.runoff.m2.s[time.step]
solve.steps(HR.backwatermodel)
##saving intermediate results
wb = dataframe.balance(HR.backwatermodel)
HR.Q.trans = rbind(HR.Q.trans, c(current.time,wb[4,2],wb[3,2],wb[2,2],wb[4,3]))
HR.h.trans = rbind(HR.h.trans, dataframe.states(HR.backwatermodel)[,2])
#create plot to generate an animation in the knitted HTML document
plot(nodes,HR.zb(nodes),col="brown",type="l",lwd=4,ylim=c(11,18),
xlab="l",ylab="h",main=paste("Transient water levels Hooge Raam"))
lines(dataframe.states(HR.backwatermodel), col = "blue", lwd = 3)
grid()
}

















































































































































































































































## creating data frames for the result of the open water model with drainage and surface runoff
HR.Q.trans = data.frame(HR.Q.trans)
colnames(HR.Q.trans) = c("time","boundary_upstream","runoff","drainage","boundary_downstream")
HR.h.trans = data.frame(HR.h.trans)
open water
\[
Total_{in} = \sum_{t=0}^{t=T} boundary_{upstream}\Delta t +
\sum_{t=0}^{t=T} runoff \Delta t + \sum_{t=0}^{t=T} drainage \Delta t\\
Total_{out} = \sum_{t=0}^{t=T} boundary_{downstream}
\]
# Water volumes for the 1D groundwater model during the total simulation time
GW.volume.drainage = sum(GW.Q.trans$boundary) * m2.day.to.m3.day * delt.t
GW.volume.runoff = sum(GW.Q.trans$surface_runoff) * m2.day.to.m3.day * delt.t
GW.volume.storage_into = sum(GW.Q.trans$storage_2flow) * m2.day.to.m3.day * delt.t
GW.volume.storage_outof = sum(GW.Q.trans$storage_2storage) * m2.day.to.m3.day * delt.t
GW.volume.precipitation = sum(GW.Q.trans$precip) * m2.day.to.m3.day * delt.t
GW.misfit = GW.volume.precipitation - GW.volume.drainage - GW.volume.runoff - GW.volume.storage_outof + GW.volume.storage_into
volume.bal.GW = data.frame(Groundwater = c("precipitation","storage_2flow","drainage","runoff","storage_2storage","total"),
Volume_in = c(GW.volume.precipitation,GW.volume.storage_into,0,0,0,sum(GW.volume.precipitation,GW.volume.storage_into)),
Volume_out = c(0,0,GW.volume.drainage,GW.volume.runoff,GW.volume.storage_outof,sum(GW.volume.drainage,GW.volume.runoff,GW.volume.storage_outof)))#,
knitr::kable(volume.bal.GW,format = "simple", caption = "Total volumes in m^3 groundwater model")
Total volumes in m^3 groundwater model
| precipitation |
1180445.5 |
0.0 |
| storage_2flow |
649463.1 |
0.0 |
| drainage |
0.0 |
493572.9 |
| runoff |
0.0 |
357520.4 |
| storage_2storage |
0.0 |
978815.7 |
| total |
1829908.6 |
1829909.0 |
NA
Check whether the output of the groundwater are the same inputs for
the open water model.
Time series analysis
It can be interesting to for example compare time series for the
precipitation and discharge of the Hooge Raam. With this, one can
examine the response of a storm event on the open water - groundwater
system.
# water volumes for the 1D open water (Hooge Raam) model during the total simulation time
HR.volume.bnd.upstream = sum(HR.Q.trans$boundary_upstream) * delt.t * 86400 #unit delt.t is in days!
HR.volume.runoff = sum(HR.Q.trans$runoff) * delt.t * 86400
HR.volume.drainage = sum(HR.Q.trans$drainage) * delt.t * 86400
HR.volume.bnd.downstream = sum(HR.Q.trans$boundary_downstream) * delt.t * 86400
HR.volume.in = HR.volume.bnd.upstream + HR.volume.runoff + HR.volume.drainage
HR.volume.out = HR.volume.bnd.downstream
## this should add up to the total amount of precipitation during the simulation time.
volume.bal.HR = data.frame(Open_water = c("inflow_upstream","surface_runoff","drainage","outflow_downstream","total"),
Volume_in = c(HR.volume.bnd.upstream,HR.volume.runoff,HR.volume.drainage,0,HR.volume.in),
Volume_out = c(0,0,0,HR.volume.bnd.downstream,HR.volume.out))
knitr::kable(volume.bal.HR,format.arg = list(digits = 8,nsmall = 3), caption = "Total volumes in m^3 open water model") #,digits = 15)
Total volumes in m^3 open water model
| inflow_upstream |
1041120.000 |
0.000 |
| surface_runoff |
357520.380 |
0.000 |
| drainage |
493572.913 |
0.000 |
| outflow_downstream |
0.000 |
1892213.340 |
| total |
1892213.293 |
1892213.340 |
NA
Zooming in for the first two days.
plot(GW.Q.trans$time, P.pattern(GW.Q.trans$time), col = "blue", lwd =2, ylab = "m/d",xlab = "days",type= "l", main = "Transient fluxes open water model in m/d", sub = "Total simulation time")
HR.discharge.m.d = HR.Q.trans$boundary_downstream * 86400 / HR.discharge.area
lines(HR.Q.trans$time,HR.discharge.m.d,col = "red", lwd =2)
HR.runoff.m.d = HR.Q.trans$runoff * 86400 / HR.discharge.area
lines(HR.Q.trans$time,HR.runoff.m.d, col = "brown",lwd = 2)
HR.drainage.m.d = HR.Q.trans$drainage * 86400 / HR.discharge.area
lines(HR.Q.trans$time,HR.drainage.m.d, col = "green",lwd =2)
grid()
legend("topright", inset=.05,
legend=c("precipitation","HR discharge","runoff","drainage"), col=c("blue","red","brown","green"),
lwd=3,horiz=FALSE)
time.max.precip = which.max(P.pattern(GW.Q.trans$time))*delt.t
abline(v=time.max.precip, col = "blue")
time.max.discharge = which.max(HR.Q.trans$boundary_downstream)*delt.t
time.max.runoff = which.max(HR.Q.trans$runoff)*delt.t
time.max.drainage = which.max(HR.Q.trans$drainage)*delt.t
abline(v=time.max.discharge,col='red',lwd=3)
abline(v=time.max.drainage, col = "green")

From the graphs it’s clearly visible that the discharge is delayed
compared to the precipitation. The max. precipitation is at day
time.max.precip (blue vertical line) and the max. discharge
is at day : time.max.discharge (red vertical line)
The moment when the maximum discharge at the weir of the Hooge Raam
is reached coincides with the max. runoff. Why? ANSWER: Runoff and
drainage both come from the same 1D groundwater model. Since this model
is 1 dimensional, from ditch to ditch, it does not contain a spatial
distribution with parcel far away and close by the Hooge Raam. Moreover
the 1D transient groundwater model calculates the effect of
precipitation on groundwater storage, drainage and surface runoff in the
same time step. In other words, precipitation is distributed over these
three groundwater sinks in the same time.
PART 4 Sensitivity analysis
Here we will consider the local sensitivity analysis.
The task is to determine what the uncertainty of a model (derived)
result is due to the used the parameter values in the model.
For example; suppose one want’s to determine the uncertainty of the
max head in a groundwater model, due to the model parameters (like kD,
boundary-conditions, precipitation, for which you not have exact, or
good values.
For this the following aspects need to be considered/determined:
derived result, like the max discharge (in time) of the Hooge
Raam
list of parameters and it optimal (assumed) values
list of the scale of variation of the parameters
local sensitivities for the parameters
scaled contributions to uncertainty of each parameter
Derived result
all results of the current coupled models:
groundwater model:
heads, \(H\), at different time
steps and locations
water balance terms(for different time steps and locations:
boundary in, boundary out (drainage)
internal flux
storage
precipitation
surface runoff
The max discharge is
HR.Q.trans$boundary_downstream[time.max.discharge] in \(m^3/s\) and takes place at time :
HR.Q.trans$time[time.max.discharge] days.
open water model:
water levels at different time steps and locations
water balance terms (for different time steps and locations)
influx upstream
outflux downstream
Parameter list
All parameters can be used for analysis of the uncertainty of the
model result, of both, models.
groundwater model:
Transmissivity of the subsoil GW.kD
Entrance resistance of the ditch C_ditch
Average drain level of the area H_drainage
Vertical resistance top layer soil
C_surface
Average surface level drainage system
H_surface
Storage coefficient; GW.S
open water model:
value weir constant (currently 1.83)
Weir crest height HR.weir.crest
Weir width HR.weir.width
Manning coefficient HR.n
River width HR.b
Side slopes HR.m
Scale of variation (\(\sigma\))
The scale of variation could be based on literature, field
experiments or for example on a model calibration.
Calculation local sensitivities
After we have determined the base model result, we will determine the
local sensitivity of the base result w.r.t. parameter; \(\frac{\partial Model_{result}}{\partial
P_i}\).
Scaled contributions to result uncertainty
ASSIGNMENT
Carry out a local sensitivity analysis for one of the model results,
the groundwater and open water model.
- Choose at least 6 parameters, preferably from both models, to carry
out the sensitivity analysis with
- Estimate the scale of variation of these parameters, based on your
experience, what you have heard during courses or simply google it
- Create chunks to determine the local sensitivities
- Make use of the pre-programmed
sensitivity.loop()
executing time loops for each model and saving intermediate data
- Create a chunk to calculate the derived uncertainties
This sensitivity.loop() contains many lines of code but
basically does the following:
- Run the transient groundwater model
- Store results, flux rates (m2/d) and heads, of the groundwater
model
- Multiply the drainage and runoff flux rates with the diffuse length
to come to m3/d and then to m3/s
- Run the transient open water model with the current drainage and
runoff flux rates
- Store the open water flux rates and open water levels
To set up a proper procedure, have close look at the Local
Sensitivity Analysis assignment 1, Local sensitivity 1D.
Derived uncertainty to analyse; the MRESULT()
For a waterboard it is important to have some insight in the way
storm events are processed within the area they control. It is therefor
important that the water managers can take measures beforehand, like
lowering the weir of the Hooge Raam before the storm event arrives.
In this example the derived uncertainty will be the the max. weir
discharge (downstream of the Hooge Raam).
There are several interesting model results for close inspection
w.r.t. their ‘derived’ uncertainties. To give some examples:
- Moment when the water levels of the Hooge Raam rises fastest
- The buffer capacity of the area, e.g. the moment when most of the
precipitation is stored in the ground
- The max. water level in the Hooge Raam
- Effect of the precipitation distribution during a storm event.
All results are stored in the following “containers” which are all
simple data frame. Simply click on them in the upper right panel
(Environmental tab) to what’s all stored;
GW.Q.trans for all flux rates of the groundwater model
in m2/d; each row is one time step
GW.H.trans for all heads in the groundwater model; each
row is one time step
HR.Q.trans for all flux rates in the open water model
in m3/s; each row is one time step
HR.H.trans for all heads in the open water model; each
row is one time step
As an example, MRESULT() is the max. discharge of the
Hooge Raam at the weir.
plot.time = GW.Q.trans$time[1:48]
plot(plot.time, P.pattern(plot.time), col = "blue", lwd =2, ylab = "m/d",xlab = "days",type= "o", main = "Transient fluxes open water model in m/d", sub = "First two days simulation time")
HR.discharge.m.d = HR.Q.trans$boundary_downstream * 86400 / HR.discharge.area
lines(HR.Q.trans$time,HR.discharge.m.d,col = "red", lwd =2)
HR.runoff.m.d = HR.Q.trans$runoff * 86400 / HR.discharge.area
lines(HR.Q.trans$time,HR.runoff.m.d, col = "brown",lwd = 2)
HR.drainage.m.d = HR.Q.trans$drainage * 86400 / HR.discharge.area
lines(HR.Q.trans$time,HR.drainage.m.d, col = "green",lwd =2)
grid()
legend("topright", inset=.05,
legend=c("precipitation","HR discharge","runoff","drainage"), col=c("blue","red","brown","green"),
lwd=3,horiz=FALSE)
time.max.precip = which.max(P.pattern(plot.time))*delt.t
abline(v=time.max.precip, col = "blue")
time.max.discharge = which.max(HR.Q.trans$boundary_downstream)*delt.t
time.max.runoff = which.max(HR.Q.trans$runoff)*delt.t
time.max.drainage = which.max(HR.Q.trans$drainage)*delt.t
abline(v=time.max.discharge,col='red',lwd=1)
abline(v=time.max.drainage, col = "green")

Be aware that MRESULT() is based on the results which
are contained in the current data frames
GW.Q.trans, QW.H.trans, HR.Q.trans, HR.H.trans. The
original value of MRESULT() is assigned to
M_base, in the code chunk of the following section “Base
run”.
Model parameters
As an example the following model parameters can be used for the
analysis;
HR.n the manning coefficient
C_ditch the entrance resistance of the ditches in the
area
HR.Qin the influx in \(m^3/s\) at the upstream end of the Hooge
Raam
H_surface the average elevation of the drained
area
H_drainage the average drain level of the drained
area
GW.S storage coefficient of the subsoil (replacement of
5)
Set up the base list for the aforementioned parameters. You may also
choose different parameters right away.
MRESULT = function()
{
max.discharge= max(HR.Q.trans$boundary_downstream)
return(max.discharge)
}
Scale of variation
Estimate the scale of variaton for the model parameters.
base = list(GW.kD = GW.kD, C_ditch = C_ditch) # the list with the current model parameters
str(base)# print the list for inspection
List of 2
$ GW.kD : num 28
$ C_ditch: num 3
Base run
To determine the sensitivities the base data need to be saved;
scale = list(GW.kD = 0.1*GW.kD, C_ditch = 0.1*C_ditch)#list of the scale of variation of the model parameters
str(scale)#print the scales for inspection
List of 2
$ GW.kD : num 2.8
$ C_ditch: num 0.3
Determine local parameter senitivities
The chosen parameters will be altered by the eps value
and reset after the run.
Next the local sensitivity of this parameter \(P_i\) w.r.t. MRESULT() will be
determined; \(\frac{\partial
\text{MRESULT}}{\partial P_i}\).
The sensitity loop function
To automate the procedure to determine the local sensitivities we
will make use of a function running the groundwater model loop and the
open water model loop in a sequence; the sensitivity.loop()
function;
Closely inspect what is carried out during one pass of this
loop.
Probably not a very familiar operator in this loop is the
<<- symbol/operator. It means that global
P, drainage, runoff,
GW.Q.trans GW.H.trans HR.Q.trans HR.h.trans data.frames and
the old.state function are adjusted within this function
avoiding a very large set of arguments to pass to this function.
M_base = MRESULT()
print(M_base)
[1] 6.49736
GW.state.base = GW.H.trans# a data.frame for the heads per time step of the groundwater model
GW.flux.base = GW.Q.trans# a data.frame for the fluxes per time step of the groundwater model
HR.state.base = HR.h.trans# a data.frame for the water levels of the Hooge Raam model
HR.flux.base = HR.Q.trans# a dataa.frame for the fluxes per time step of the Hooge Raam model
eps = 0.01 #1% of the original value hopefully avoiding rounding errors and still be in de proper local domain.
Local sensitivities
Each local sensitivity can now be determined using a sequence of:
- adding
eps to the current parameter \(P_i\)
- running the
Sensitivity.loop()
- calculating \(\frac{\partial
\text{MRESULT()}}{\partial P_i}\)
- subtracting
eps from the current parameter.
Set up the sensitivity sequence, see above, to determine the local
sensitivities for the chosen parameters.
TIP: you can use eps being an offset
so, \(P_i = P_i + eps\) or use it as a
fraction: \(P_i = P_i*(1 + eps)\)
Sensitivity.loop = function()
{
# the groundwater model loop, GW model first because we use the drainage and runoff to the backwater model, after that run backwater model
#data container for results
GW.Q.trans = c()
GW.H.trans = c()
temp.runoff = c()
#using the stationary head for the initial head for the first time step for the transient model
old.state <<- state.fun(GW.stat)
delt.t = 1/24 # 1 hour
start.time = 0
end.time = 10.0
current.time = start.time
while (current.time < end.time)
{
#time stepping
current.time = current.time + delt.t
#Groundwater model run
P <<- P.pattern(current.time) #should be a global variable, hence <<-, for the GW.trans model
solve.steps(GW.trans)
# plot(GW.trans,fluxplot = T)
#save intermediate data
wb = dataframe.balance(GW.trans)
GW.Q.trans = rbind(GW.Q.trans, c(current.time,wb[2,3],wb[3,2],wb[3,3],wb[4,2],wb[5,3]))
GW.H.trans = rbind(GW.H.trans, dataframe.states(GW.trans)[,2])
#save intermediate data
old.state <<- state.fun(GW.trans)
}
#browser()
# Storing data
GW.Q.trans = data.frame(GW.Q.trans)
colnames(GW.Q.trans) = c("time", "surface_runoff","storage_in","storage_out","precip","boundary")
GW.H.trans = data.frame(GW.H.trans)
# Scaling the groundwater fluxes to lateral influxes for the open water model
Q.drainage.m3.d = GW.Q.trans$boundary * m2.day.to.m3.day
Q.drainage.m3.s = Q.drainage.m3.d/day2sec
Q.drainage.m2.s = Q.drainage.m3.s/HR.length
Q.runoff.m3.d = GW.Q.trans$surface_runoff * m2.day.to.m3.day
Q.runoff.m3.s = Q.runoff.m3.d/day2sec
Q.runoff.m2.s = Q.runoff.m3.s/HR.length
## the open water model loop
#data containers for results
HR.Q.trans = c()
HR.h.trans = c()
HR.Q_upstream = c()
HR.Q_downstream = c()
#data container for results
#time steps for the loop
current.time = start.time
#time step for retrieving data from drainage and surface time series of the groundwater model
time.step =start.time
while(current.time < end.time)
{
current.time = current.time + delt.t
time.step = time.step + 1
drainage <<- Q.drainage.m2.s[time.step] #global variable for global HR.backwatermodel
runoff <<- Q.runoff.m2.s[time.step] #global variable for global HR.backwatermodel
solve.steps(HR.backwatermodel)
##saving intermediate results
wb = dataframe.balance(HR.backwatermodel)
HR.Q.trans = rbind(HR.Q.trans, c(current.time,wb[4,2],wb[3,2],wb[2,2],wb[4,3]))
HR.h.trans = rbind(HR.h.trans, dataframe.states(HR.backwatermodel)[,2])
##saving intermediate results
}
#browser()
HR.Q.trans = data.frame(HR.Q.trans)
colnames(HR.Q.trans) = c("time","boundary_upstream","runoff","drainage","boundary_downstream")
HR.h.trans = data.frame(HR.h.trans)
#returning the new data.frames to the global environment for further analysis.
GW.Q.trans <<- GW.Q.trans
GW.H.trans <<- GW.H.trans
HR.Q.trans <<- HR.Q.trans
HR.h.trans <<- HR.h.trans
}
Total and partial variances
Recall the previous Local Sensitivity Assignment where you calculated
the:
- variances for each parameter based on its scale of variance and the
local sensitivity of that parameter w.r.t.
MRESULT()
- calculate the sum of these variances
- calculate the relative contribution of each parameter to the total
variance
- plot a pie chart to visualize the contributions to the derived
uncertainty
- a table of fractions,
knitr::kable() is already
implemented to inspect the procentual sensitivities
Determine the derived uncertainty based on the aforementioned
list
#a table for some results "relvarM" contains the relative variances of MRESULT
knitr::kable(as.data.frame(relvarM)*100, caption = "percentage local sensitivities",align="c")
1.0095225
LS0tDQp0aXRsZTogIkhvb2dlIFJhYW0gb3BlbiB3YXRlciB3aXRoIGdyb3VuZHdhdGVyIGludGVyYWN0aW9ucyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIGNzczogd2FudF9uLmNzcw0KICAgIGRmX3ByaW50OiBwYWdlZA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgY3NzOiB3YW50X24uY3NzDQogIHBkZl9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KLS0tDQoNCiMgSW50cm9kdWN0aW9uIGNoYW5nZQ0KDQoNCldpdGggdGhpcyBmaW5hbCBhc3NpZ25tZW50IGJvdGggYW4gb3BlbiB3YXRlciBtb2RlbCBhbmQgYSBncm91bmR3YXRlciBtb2RlbCB3aWxsIGJlIGRldmVsb3BlZCB3aGljaCB3aWxsIGJlIGNvdXBsZWQuICANCkRlIG9wZW4gd2F0ZXIgbW9kZWwgcmVwcmVzZW50cyBhIHNtYWxsIHJpdmVyIGNhbGxlZCB0aGUgSG9vZ2UgUmFhbS4gVGhlIGdyb3VuZHdhdGVyIG1vZGVsIHdpbGwgc2ltdWxhdGUgdGhlIHRyYW5zaXRpb24gb2YgcHJlY2lwaXRhdGlvbiBpbnRvIGRyYWluYWdlIGFuZCBzdXJmYWNlIHJ1bm9mZiBvZiB0aGUgYXJlYSBzdXJyb3VuZGluZyB0aGUgSG9vZ2UgUmFhbS4gIA0KRmxvdyBpbiB0aGUgb3BlbiB3YXRlciBtb2RlbCBpcyBiYXNlZCBvbiB0aGUgZGlmZnVzaXZlIHdhdmUgKCJGcm91ZGUgPSAwIikgYXBwcm94aW1hdGlvbiBpbiAxRC4gR3JvdW5kd2F0ZXIgZmxvdyBpcyBiYXNlZCBvbiBEYXJjeSdzIGVxdWF0aW9uIGFuZCBzaW11bGF0ZXMgdGhlIGZsb3cgYmV0d2VlbiB0d28gb3BlbiB3YXRlciBjb3Vyc2VzIChkaXRjaGVzIG9yIGRyYWlucykgaW4gMUQuICBHcm91bmR3YXRlciBmbG93IHdpbGwgYmUgc2ltdWxhdGVkIGluIHRyYW5zaWVudCBtb2RlIHRvIGFjY291bnQgZm9yIHN0b3JhZ2UgY2hhbmdlcy4gVGhlIG9wZW4gd2F0ZXIgZmxvdyBtb2RlbCBzaW11bGF0ZXMgaW4gcHNldWRvIHN0YXRpb25hcnkgbW9kZS4gIA0KQSBzdG9ybSBldmVudCwgYSBoZWF2eSByYWluIHNob3dlciwgaXMgdGhlIGZvcmNpbmcgZm9yIHdoaWNoIHdlIHdpbGwgaW52ZXN0aWdhdGUgZmxvdyBmcm9tIHRoZSBzdXJmYWNlIGludG8gdGhlIHNvaWwsIHRvd2FyZHMgZGl0Y2hlcyBhbmQgZmluYWxseSB0byB0aGUgSG9vZ2UgUmFhbSB0byBnZXQgZGlzY2hhcmdlZCBhdCB0aGUgd2VpciBvbiB0aGUgbG93ZXIgc2lkZS4NCg0KVGhlIEhvb2dlIFJhYW0gaXMgbG9jYXRlZCBqdXN0IGJlbG93IHRoZSBzbWFsbCB0b3duIEdyYXZlIGFuZCBpcyBwYXJ0IG9mIHRoZSB3YXRlciBib2FyZCAiQWEgZW4gTWFhcyIuIFRoZSBzdXJyb3VuZGluZyBhcmVhIGlzIG1haW5seSB1c2VkIGFzIGdyYXNzbGFuZHMsIHNvbWUgY29ybmZpZWxkcyBhbmQgYSBmZXcgZm9yZXN0IHBsb3RzLiBUaGUgYXJlYSBpcyByZWFzb25hYmx5IGZsYXQgd2hlcmUgc3VyZmFjZSBsZXZlbHMgcmFuZ2UgZnJvbSAxNS41IHRpbGwgYWJvdXQgMTcuNSBtIEFNU0wgKEFib3ZlIE1lYW4gU2VhIExldmVsKS4NCg0KVGhlIGZpZ3VyZSBiZWxvdyBnaXZlcyBhbiBvdmVydmlldyBvZiB0aGUgSG9vZ2UgUmFhbSB3aGljaCB3aWxsIGJlIGNvbnNpZGVyZWQgZm9yIG1vZGVsaW5nLg0KDQohW092ZXJ2aWV3IEhvb2dlIFJhYW0gYW5kIGFyZWFdKEhvb2dlLXJhYW1fb3ZlcnZpZXcucG5nKQ0KDQpUaGUgZmlyc3QgcGFydCBjb250YWlucyB0aGUgZXhwbGFuYXRpb24gYW5kIGFzc2lnbm1lbnRzIGZvciB0aGUgb3BlbiB3YXRlciBtb2RlbCwgdGhlIHNlY29uZCB3aWxsIGdvIGludG8gdGhlIGRldGFpbHMgb2YgdGhlIGdyb3VuZHdhdGVyIG1vZGVsLCB0aGUgY291cGxpbmcgb2YgYm90aCBtb2RlbHMgaXMgZGVzY3JpYmVkIGluIHRoZSB0aGlyZCBwYXJ0IGFuZCBmaW5hbGx5IHRoZSBsYXN0IHBhcnQgKDQpIGNvbnRhaW5zIHRoZSBzZXR1cCB0byBkZXRlcm1pbmUgZGVyaXZlZCB1bmNlcnRhaW50aWVzIG9mIHRoZSAibW9kZWwtdHJhaW4iLg0KDQojIFBBUlQgMSB0aGUgT3BlbiB3YXRlciBtb2RlbA0KDQojIyBPcGVuIHdhdGVyIGVxdWF0aW9ucw0KDQpUaGlzIGRvY3VtZW50IHNob3VsZCBnaXZlIGFuIGludHJvZHVjdGlvbiB0byB0aGUgaHlkcmF1bGljIG1vZGVsaW5nIG9mIHRoZSBIb29nZSBSYWFtIHJpdmVyLg0KDQpBbiBhdHRlbXB0IGlzIG1hZGUgdG8gbWFrZSB0aGUgZG9jdW1lbnQgc2VsZiBjb250YWluZWQuIEZvciB0aGF0IHJlYXNvbiB3ZSBzdGFydCBieSBnaXZpbmcgc29tZSBiYXNpYyBmb3JtdWxhcywgYW5kIG1vcmUgZm9ybXVsYXMgd2lsbCBmb2xsb3cgZnVydGhlciBpbiB0aGUgZG9jdW1lbnQuIFRoaXMgZG9jdW1lbnQgc2hvdWxkIGhvd2V2ZXIgbm90IHRvIGJlIGNvbnNpZGVyZWQgYXMgYSBjb3Vyc2UgaW4gaHlkcm9keW5hbWljcy4gVGhlIGZvcm11bGFzIGFyZSBjaXRlZCAod2hpY2ggc2hvdWxkIGJlIGZvciBtb3N0IG9mIHlvdSBhIHJlcGV0aXRpb24/KSB0byBmb3JtIHRoZSBiYXNlIG9mIHRoZSBjb2RlLg0KDQpUaGUgZmxvdyBpbiByaXZlcnMgYXMgdGhlIEhvb2dlIFJhYW0gaXMgbW9zdCBvZnRlbiBkZXNjcmliZWQgYnkgdGhlIHNvIGNhbGxlZCBTdC1WZW5hbnQgZXF1YXRpb25zLCBleHByZXNzaW5nIHJlc3BlY3RpdmVseSB0aGUgbWFzcyBhbmQgdGhlIG1vbWVudHVtIGJhbGFuY2UgKG9ubHkgaW4gKngqLWRpcmVjdGlvbjoNCg0KJCQNClxmcmFje1xwYXJ0aWFsIEF9e1xwYXJ0aWFsIHR9ICsgXGZyYWN7XHBhcnRpYWwgUX17XHBhcnRpYWwgeH0gPSBJXFwNClxmcmFje1xwYXJ0aWFsIFF9e1xwYXJ0aWFsIHR9ICsgXGZyYWN7XHBhcnRpYWwgUVwsdX17XHBhcnRpYWwgeH0gDQogICAgICAgICAgICA9IGdcO0FcO1xCaWcoIFNfbyAtIFNfZiAtIFxmcmFje1xwYXJ0aWFsIGF9e1xwYXJ0aWFsIHh9XEJpZykNCiQkDQoNCkFzIHdlIGFyZSBoZXJlIGxlc3MgaW50ZXJlc3RlZCBpbiBoaWdobHkgZHluYW1pYyBvcGVuIHdhdGVyIGNhbGN1bGF0aW9ucywgYSBzaW1wbGlmaWNhdGlvbiBvZiB0aGUgc2Vjb25kIGVxdWF0aW9uIGFib3ZlIHdpbGwgYmUgdXNlZC4gVGhpcyBzaW1wbGlmaWNhdGlvbiBzdGFydHMgZnJvbSB0aGUgb2JzZXJ2YXRpb24gdGhhdCBpbiBtYW55IHNpdHVhdGlvbnMgKGNlcnRhaW5seSBsb3dsYW5kIHNpdHVhdGlvbnMpIHRoZSBmaXJzdCB0d28gdGVybXMgaW4gdGhlIG1vbWVudHVtIHBhcnQgb2YgdGhlIFN0LVZlbmFudCBlcXVhdGlvbnMgYXJlIG11Y2ggc21hbGxlciB0aGFuIHRoZSB0ZXJtcyBvbiB0aGUgcmlnaHQgaGFuZCBzaWRlLg0KDQokJA0KXGZyYWN7XHBhcnRpYWwgUX17XHBhcnRpYWwgdH0gKyBcZnJhY3tccGFydGlhbCBRXCx1fXtccGFydGlhbCB4fSA9IA0KICAgICAgICBnXDtBXDtcQmlnKCBTX28gLSBTX2YgLSBcZnJhY3tccGFydGlhbCBhfXtccGFydGlhbCB4fVxCaWcpXFwNClxEb3duYXJyb3cgXFwNCjAgPSBnXDtBXDtcQmlnKCBTX28gLSBTX2YgLSBcZnJhY3tccGFydGlhbCBhfXtccGFydGlhbCB4fVxCaWcpXFwNClxEb3duYXJyb3cgXFwNCjAgPSAgU19vIC0gU19mIC0gXGZyYWN7XHBhcnRpYWwgYX17XHBhcnRpYWwgeH0NCiQkDQoNClRoZSBtZWFuaW5nIG9mIHRoZSB0ZXJtcyBpbiB0aGVzZSBlcXVhdGlvbnMgd2lsbCBiZSBleHBsYWluZWQgd2hlbiB0aGV5IGZpcnN0IGFwcGVhciBpbiB0aGlzIGRvY3VtZW50Lg0KDQpJbiB0aGVzZSBleGVyY2lzZXMgc2l0dWF0aW9ucyB3aWxsIGJlIHN0dWRpZWQgd2hlcmUNCg0KLSAgIHRoZSBmbG93IGluIHRoZSBIb29nZSBSYWFtIGNhbiBiZSBjb25zaWRlcmVkIHRvIGJlICpzdGF0aW9uYXJ5KiAoc28gdGhlIHRpbWUgZGVyaXZhdGl2ZXMgaW4gdGhlIGVxdWF0aW9ucyBhYm92ZSBkaXNhcHBlYXIpDQotICAgdGhlcmUgaXMgYSB3ZWlyIGF0IHRoZSBkb3duc3RyZWFtIGVuZCBvZiB0aGUgcml2ZXINCg0KU2l0dWF0aW9ucyBvZiB0aGlzIHR5cGUgYXJlIG9mdGVuIGNhbGxlZCAqKmJhY2t3YXRlciBjdXJ2ZXMqKi4NCg0KVGhpcyB0eXBlIG9mIG9wZW4gd2F0ZXIgbW9kZWwgdGhhdCB3aWxsIGJlIGRldmVsb3BlZCBpbiB0aGlzIGRvY3VtZW50IHdpbGwgYmUgY291cGxlZCB3aXRoIGEgZ3JvdW5kd2F0ZXIgbW9kZWwuIFNvIGF0IHNvbWUgcGxhY2VzIHR5cGljYWwgZ3JvdW5kd2F0ZXIgdGVybXMgYW5kIGRpbWVuc2lvbnMgbWF5IG9jY3VyLg0KDQpUaGUgb3BlbiB3YXRlciBoYXMgaXRzIG93biBzdGFuZGFyZCB1bml0czoNCg0KLSAgIGxlbmd0aCB1bml0ID0gJG0kIG1ldGVyDQotICAgdGltZSB1bml0ID0gJHMkIHNlY29uZA0KDQojIyBIb29nZSBSYWFtIGRpbWVuc2lvbnMgYW5kIHBhcmFtZXRlcnMNCg0KV2UgYXJlIGdvaW5nIHRvIHNpbXVsYXRlIHRoZSBvcGVuIHdhdGVyIGZsb3cgb2YgdGhlIEhvb2dlIFJhYW0gc3RhcnRpbmcgYXQgdGhlIHNvdXRoZXJuIHBhcnQgYXQgdGhlICJWbGllc3dlZyIgd2l0aCBhIHByZXNjcmliZWQgZmx1eCBjb21pbmcgZnJvbSB0aGUgZGlzY2hhcmdpbmcgdXBzdHJlYW0gYXJlYS4gQXQgdGhlIG5vcnRoZXJuIHBhcnQgb2YgdGhlIEhvb2dlIFJhYW0gc2VjdGlvbiBpdCBkaXNjaGFyZ2VzIHRocm91Z2ggYSB3ZWlyLCB3aGljaCBmaW5hbGx5IGlzIGdldHRpbmcgZGlzY2hhcmdlZCBpbnRvIHRoZSBNZXVzZS4NCg0KV2Ugd2lsbCB1c2UgdGhlIGZvbGxvd2luZyBkYXRhIGZvciBkaW1lbnNpb25pbmcgdGhlIHJpdmVyLiBEYXRhIGlzIGJhc2VkIG9uICJsZWdnZXIiIHdhdGVyYm9hcmQgQWEgZW4gTWFhcy4NCg0KWW91IG1heSB3YW50IHRvIHF1aWNrbHkgYnJvd3NlIHRocm91Z2ggdGhpcyAibGVnZ2VyIiB0byBzZWUgd2hhdCBpbmZvcm1hdGlvbiBpcyBhdmFpbGFibGUuIEdvIHRvIGh0dHBzOi8vd3d3LmFhZW5tYWFzLm5sL29uc3dlcmsvcmVnZWxzL2xlZ2dlci8gYW5kIG9wZW4gdGhlICdMZWdnZXIgb3BwZXJ2bGFrdGV3YXRlcicuDQoNCg0KVGhlIGxlbmd0aCBvZiB0aGlzIHJlYWNoIG9mIHRoZSBIb29nZSBSYWFtIGlzIDE0NzAgbS4gVXBzdHJlYW0gYm90dG9tIGxldmVsIDE0LjUwIG0gQU1TTCwgZG93bnN0cmVhbSBib3R0b20gbGV2ZWwgMTEuODAgbSBBTVNMLCAoYXZlcmFnZSkgYm90dG9tIHdpZHRoIDIuMTAgbSwgKGF2ZXJhZ2UpIHNpZGUgc2xvcGUgMS41IG0vbS4NCg0KV2VpcjogY3Jlc3Qgd2lkdGggMi4wIG0sIGNyZXN0IGhlaWdodDogMTEuNDUgYW5kIDEyLjYwIG0uDQoNCkluZmx1eCBzdGF0aW9uYXJ5IHVwc3RyZWFtIGJhc2VkIG9uIGJhc2UgZmxvdyBhcyBkaXNjaGFyZ2Ugb2YgYW4gdXBzdHJlYW0gYXJlYSBvZiAyNTAgaGEgKGFzc3VtZSBhIGRpc2NoYXJnZSBvZiAwLjUgbC9zL2hhKS4NCg0KYGBge3J9DQpybShsaXN0ID0gbHMoKSkNCkhSLlFpbiA9IDI1MCowLjAwNSAgIzI1MGhhICogMC41IGwvcy9oYQ0KY2F0KCdUb3RhbCBpbmZsdXggdXBzdHJlYW0gOiAnLEhSLlFpbikNCmBgYA0KDQojIyBMb25naXR1ZGluYWwgdmlldw0KDQpJdCBpcyBjb252ZW50aW9uYWwgdG8gbWVhc3VyZSB0aGUgbGVuZ3RoIGFsb25nIHRoZSByaXZlciBmcm9tIHVwc3RyZWFtIHRvIGRvd25zdHJlYW0uIFRoZSBkb21haW4gb2YgdGhlIHJpdmVyIHN0YXJ0cyBhdCAwIG0uDQoNCldlIHdpbGwgYWxzbyBuZWVkIHRoZSBib3R0b20gc2xvcGUgaW4gd2hhdCBmb2xsb3dzLiBJbiB0aGUgZXF1YXRpb25zIG9mIHRoZSBpbnRyb2R1Y3Rpb24gdGhpcyBzbG9wZSB3YXMgY2FsbGVkICRTX28kLiBJdCBpcyBkZWZpbmVkIGFzIHRoZSBkcm9wIG9mIGJvdHRvbSBsZXZlbCBwZXIgdW5pdCBsZW5ndGggb2YgdGhlIHJpdmVyLiBIZXJlIGl0IGlzIGp1c3QgYSBjb25zdGFudDoNCg0KYGBge3IsIGV2YWw9VFJVRX0NCkhSLmxlbmd0aCA9IDE0NzANCkhSLmRvbWFpbiA9IGMoMCxIUi5sZW5ndGgpDQpIUi5ib3RlbGV2LnVwc3RyZWFtID0gMTQuNTANCkhSLmJvdGVsZXYuZG93bnN0cmVhbSA9IDExLjgwDQpIUi5TbyA9IChIUi5ib3RlbGV2LnVwc3RyZWFtIC1IUi5ib3RlbGV2LmRvd25zdHJlYW0pLyhIUi5sZW5ndGgpICMlIGJvdGVsZXYudXBzdHJlYW0gIyUgYm90ZWxldi5kbnN0cmVhbSAjJSBsZW5ndGgNCmNhdCgnU28gPSAnLEhSLlNvKQ0KDQpIUi56YiA9IGFwcHJveGZ1bihIUi5kb21haW4sYyhIUi5ib3RlbGV2LnVwc3RyZWFtLEhSLmJvdGVsZXYuZG93bnN0cmVhbSksDQogICAgICAgICAgICAgICAgICBydWxlPTIpDQpwbG90KEhSLmRvbWFpbixIUi56YihIUi5kb21haW4pLHR5cGUgPSAibCIsY29sPSJicm93biIsbHdkPTQsDQogICAgIG1haW49Ikhvb2dlIFJhYW0gYmVkIGJvdHRvbSIseGxhYj0ieCAobSkiLCB5bGFiPSAieiAobSkiKQ0KZ3JpZCgpDQpgYGANCg0KDQpUaGlzIGJvdHRvbSBzbG9wZSBicmluZ3MgdGhlIGdyYXZpdHkgaW50byB0aGUgZXF1YXRpb25zOiB0aGUgaGlnaGVyIHRoaXMgc2xvcGUsIHRoZSBsYXJnZXIgdGhlIGluZmx1ZW5jZSBvZiB0aGUgZ3Jhdml0eSBvbiB0aGUgd2F0ZXIgZmxvdy4NCg0KIyMgQ3Jvc3Mgc2VjdGlvbiBnZW9tZXRyeQ0KDQpUaGUgY3Jvc3Mgc2VjdGlvbiBjYW4gaW4gZ2VuZXJhbCBoYXZlIGEgY29tcGxleCBhbmQgc3BhdGlhbGx5IHZhcnlpbmcgZm9ybS4gSGVyIHdlIHRha2UganVzdCBhIHNpbXBsZSB0cmFwZXpvaWRhbCBwcm9maWxlIHdpdGggYSBjb25zdGFudCBib3R0b20gd2lkdGggJGIkIGFuZCBjb25zdGFudCBzaWRlIHNsb3BlICRtJDoNCg0KYGBge3IsIGV2YWw9VFJVRX0NCg0KSFIuYj0yLjEgICAjIGJvdHRvbSAgd2lkdGgNCkhSLm09MS41ICAgIyBzaWRlIHNsb3BlDQpgYGANCg0KVGhlIHdhdGVyIGxldmVsIHdpdGggcmVzcGVjdCB0byB0aGUgYm90dG9tIG9mIHRoaXMgY3Jvc3Mgc2VjdGlvbiBpcyBjYWxsZWQgdGhlICp3YXRlciBkZXB0aCogYW5kIHdpbGwgYmUgZGVub3RlZCBieSAkYSQuIFRvIG1ha2UgYSBwbG90IG9mIHRoZSBjcm9zcyBzZWN0aW9uIHdlIG5lZWQgdG8gY2FsY3VsYXRlIHRoZSB3aWR0aCBmb3IgYSB3aG9sZSByYW5nZSBvZiBwb3NzaWJsZSB3YXRlciBkZXB0aHMuDQoNCkZvciBhIHRyYXBlem9pZGFsIGNyb3NzIHNlY3Rpb24gdGhpcyByZXN1bHRzIGluOg0KDQpgYGB7ciwgZXZhbD1UUlVFfQ0KDQpIUi53aWR0aCA9IGZ1bmN0aW9uKGEpDQp7DQogIHJldHVybihIUi5iKzIqSFIubSphKQ0KfQ0KYGBgDQoNClRoZSBuZXh0IGNodW5rIGNyZWF0ZXMgYSBwbG90IG9mIHRoZSBjcm9zcyBzZWN0aW9uDQoNCmBgYHtyLCBldmFsPVRSVUV9DQoNCmFyYW5nZT1zZXEoMCwxLjUsbGVuZ3RoPTEwMCkgIyBsYXJnZSBlbm91Z2ggb2YgcG9zc2libGUgZGVwdGggdmFsdWVzIA0Kd2lkdGhyYW5nZSA9IEhSLndpZHRoKGFyYW5nZSkNCnBsb3QoYygtcmV2KHdpZHRocmFuZ2UvMiksd2lkdGhyYW5nZS8yKSxjKHJldihhcmFuZ2UpLGFyYW5nZSksDQogICAgIHhsYWI9InkiLHlsYWI9ImEiLG1haW49ImNyb3NzIHNlY3Rpb24iLHR5cGU9ImwiLGx3ZD01LGNvbD0iYnJvd24iKQ0KZ3JpZChjb2w9ImJsYWNrIikNCmBgYA0KDQojIyBXZXR0ZWQgYXJlYQ0KDQpPbmUgb2YgdGhlIGltcG9ydGFudCBjcm9zcyBzZWN0aW9uIGZ1bmN0aW9ucyBpcyB0aGUgd2V0dGVkIGFyZWEuIEl0IHdhcyBpbiB0aGUgU3QtVmVuYW50IGVxdWF0aW9uIGRlbm90ZWQgYnkgJEEkLiBGb3IgYSB0cmFwZXpvaWRhbCBjcm9zcyBzZWN0aW9uIHRoaXMgY2FuIGJlIGVhc2lseSBjYWxjdWxhdGVkIGJ5IHRoZSBmb2xsb3dpbmcgZnVuY3Rpb246DQoNCmBgYHtyLCBldmFsPVRSVUV9DQoNCkhSLkEgPSBmdW5jdGlvbihhKQ0Kew0KICByZXR1cm4oSFIuYiphK0hSLm0qYV4yKQ0KfQ0KYGBgDQoNCk9uZSBvZiB0aGUgcmVhc29ucyB0aGF0IHRoaXMgd2V0dGVkIGNyb3NzIHNlY3Rpb24gaXMgc28gaW1wb3J0YW50IGlzIGJlY2F1c2Ugb2YgdGhlIGltcG9ydGFudCBmb3JtdWxhICRRID0gdiBBJCwgd2VyZSAkUSQgaXMgdGhlIGRpc2NoYXJnZSwgJHYkIGlzIHRoZSB2ZWxvY2l0eSBhbmQgJEEkIGlzIHRoZSB3ZXR0ZWQgY3Jvc3Mgc2VjdGlvbi4gDQpTb21lIHR5cGljYWwgKG1heCkgdmVsb2NpdGllcyBkZXBlbmRpbmcgb2YgdGhlIHNvaWwgdHlwZSBhcmUgZ2l2ZW4gdGhlIHRhYmxlIGJlbG93ICANCg0KfCBTb2lsIHR5cGUgICAgICAgICAgIHwgdmVsb2NpdHkgbS9zICAgfA0KfDotLS0tLS0tLS0tLS0tLS0tLS0tOnw6LS0tLS0tLS0tLS0tLS06fA0KfCBjbGF5L2xvYW0vbG9lc3MgICAgIHwgMC42MCAtIDAuODAgICAgfA0KfCBzYW5kL3NvbGlkIHBlYXQgICAgIHwgMC4zMCAtIDAuNjAgICAgfA0KfCBjb2Fyc2Ugc2FuZCAgICAgICAgIHwgMC4yMCAtIDAuNTAgICAgfA0KfCBmaW5lIHNhbmQvc29mdCBwZWF0IHwgMC4xNSAtIDAuMzAgICAgfA0KDQo6IHNvdXJjZTogQ3VsdHV1cnRlY2huaXNjaCBWYWRlbWVjdW0gMTk4OA0KDQpBcyBjYW4gYmUgc2VlbiBpbiB0aGUgZnVuY3Rpb24gYWJvdmUgdGhhdCB0aGUgd2V0dGVkIGNyb3NzIHNlY3Rpb24gaXMgZGVwZW5kZW50IG9uIHRoZSB3YXRlciBkZXB0aCAkYSQuIE9uZSB3YXkgdG8gc2VlIHRoZSBpbmZsdWVuY2Ugb2YgdGhlIHdldHRlZCBjcm9zcyBzZWN0aW9uIG9uIHRoZSBkaXNjaGFyZ2UgaXMgdG8gaW52ZXN0aWdhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuICRRJCBhbmQgJGEkIGZvciBmaXhlZCB2ZWxvY2l0aWVzLiBIZXJlIGlzIGEgdHlwaWNhbCBleGFtcGxlIChpdCBpcyBjdXN0b21hcnkgdG8gcGxvdCB3YXRlciBkZXB0aHMgb24gdGhlIHZlcnRpY2FsIGF4aXMpOg0KDQpgYGB7ciwgZXZhbD1UUlVFfQ0KQXJhbmdlID0gIEhSLkEoYXJhbmdlKQ0KdmVsID0gMC41MCAjbS9zIHZlbG9jaXR5IGZvciBjb2Fyc2Ugc2FuZA0KUXJhbmdlID0gdmVsKkFyYW5nZQ0KcGxvdChRcmFuZ2UsYXJhbmdlLA0KICAgICBtYWluPSJIb29nZSBSYWFtIFEtYSByZWxhdGlvbiBmb3IgZml4ZWQgdmVsb2NpdHkgdiIsDQogICAgIHhsYWI9IlEgKG1eMy9zKSIseWxhYj0iYSAobSkiLGNvbD0iYnJvd24iLGx3ZD0zLHR5cGU9ImwiKQ0KbGVnZW5kKCJib3R0b21yaWdodCIsIGluc2V0PS4wNSwgdGl0bGU9InYgKG0vcykiLA0KICAgICAgIGMoIjAuNSIpLCBjb2w9YygiYnJvd24iKSxsd2Q9Myxob3Jpej1UUlVFKQ0KZ3JpZChjb2w9ImJsYWNrIikNCmBgYA0KDQpWZWxvY2l0aWVzIGhpZ2hlciB0aGFuIDEgbS9zIGFyZSBob3dldmVyIHJhdGhlciBhdHlwaWNhbC4NCg0KDQo8ZGl2IGNsYXNzPSJxdWVzdGlvbiI+DQpGaWxsIHRoZSBjaHVuayBiZWxvdyAocmVwbGFjZSBhbGwgWFhYKSB3aXRoIGEgY29kZSB0aGF0IGNvbWJpbmVzIGluIG9uZVwNCnBsb3QgdGhlIGEtUSBmb3IgZm91ciByZWFsaXN0aWMgdmVsb2NpdGllcy4NCg0KYGBge3IsIGV2YWw9VFJVRX0NCkFyYW5nZSA9ICBIUi5BKGFyYW5nZSkgI0NhbGN1bGF0aW5nIHdldHRlZCBhcmVhDQpRMXJhbmdlID0gMC4xNSpBcmFuZ2UgICNDbGF5L2xvYW0vbG9lc3MgdmVsb2NpdHkNClEycmFuZ2U9ICAwLjIwKkFyYW5nZSAgICNTYW5kL3NvbGlkIHBlYXQgdmVsb2NpdHkNClEzcmFuZ2U9ICAwLjMwKkFyYW5nZSAgI0NvYXJzZSBzYW5kIA0KUTRyYW5nZSA9IDAuNjAqQXJhbmdlICAgICAjRmluZSBzYW5kL3NvZnQgcGVhdA0KcGxvdChRNHJhbmdlLGFyYW5nZSwgICAjTWFrZSBhIHBsb3Qgb2YgZmluZSBzYW5kDQogICAgIG1haW49Ikhvb2dlIFJhYW0gUS1hIHJlbGF0aW9uIGZvciBmaXhlZCB2ZWxvY2l0eSB2IiwgI1RpdGxlDQogICAgIHhsYWI9ZXhwcmVzc2lvbihRfihtXjMvcykpLHlsYWI9ImEgKG0pIixjb2w9ImJyb3duIixsd2Q9Myx0eXBlPSJsIiwgeWxpbT1jKDAsMS41KSwgeGxpbSA9IGMoMCwyKSkgI1NldHRpbmdzIGZvciBwbG90DQpsaW5lcyhRM3JhbmdlLGFyYW5nZSxsd2Q9Myxjb2w9ImJsdWUiKSAjQWRkaW5nIHBsb3Qgb2YgY29hcnNlIHNhbmQNCmxpbmVzKFEycmFuZ2UsYXJhbmdlLGx3ZD0zLGNvbD0icmVkIikgICNBZGRpbmcgcGxvdCBvZiBzYW5kL3NvbGlkIHBlYXQNCmxpbmVzKFExcmFuZ2UsYXJhbmdlLGx3ZD0zLGNvbD0iZ3JlZW4iKSAjQWRkaW5nIHBsb3Qgb2YgY2xheS9sb2FtL2xvZXNzDQoNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCBpbnNldD1jKDAuMDAxKSwgdGl0bGU9InYgKG0vcykiLCAjQWRkaW5nIHRoZSBsZWdlbmQNCmMoImNsYXksIDAuMTUiLCJzYW5kLCAwLjIwIiwiY29hcnNlIHNhbmQsIDAuMzAiLCJmaW5lIHNhbmQsIDAuNjAiKSwgY29sPWMoImdyZWVuIiwicmVkIiwiYmx1ZSIsImJyb3duIiksbHdkPTMsaG9yaXo9VFJVRSwgY2V4ID0gMC42KSAjQ29sb3IgdGhlIGRpZmZlcmVuY2Ugc2NlbmFyaW8NCg0KZ3JpZChjb2w9ImJsYWNrIikgI01ha2luZyB0aGUgY29sb3Igb2YgdGhlIGdyaWQgdG8gYmUgYmxhY2sNCg0KDQpgYGANCjwvZGl2Pg0KDQoNCg0KIyMgRXF1aWxpYnJpdW0gZGlzY2hhcmdlDQoNCkJ1dCBvZiBjb3Vyc2UgdXN1YWxseSBib3RoIGFuZCAkQSQgYW5kICR2JCBjaGFuZ2UgaWYgdGhlIHdhdGVyIGRlcHRoICRhJCBjaGFuZ2VzLg0KDQpGb3IgZXF1aWxpYnJpdW0gc2l0dWF0aW9ucyB0aGlzIHJlbGF0aW9uc2hpcCBjYW4gYmUgaW52ZXN0aWdhdGVkIHRocm91Z2ggZm9ybXVsYXMuIEVxdWlsaWJyaXVtIG1lYW5zIHRoYXQgdGhlIHdhdGVyIGRlcHRoIGlzIGNvbnN0YW50IGluIHNwYWNlICgkXGZyYWN7XHBhcnRpYWwgYX17XHBhcnRpYWwgeH0gPSAwJCkgaW4gdGVybXMgb2YgdGhlIFN0LVZlbmFudCBlcXVhdGlvbnMgb2YgdGhlIGludHJvZHVjdGlvbikgYW5kIHRpbWUuIEZvciB0aGlzIHNpdHVhdGlvbiB0aGUgb3BlbiB3YXRlciBlcXVhdGlvbiBzaW1wbGlmaWVzIGludG87ICQkU18wID0gU19mID0gXGZyYWN7bl4yXDsgUV4yfXtBXjJcOyBSXns0LzN9fSQkICAgDQoNCkZyb20gdGhpcyBvbmUgY2FuIGRlcml2ZTogJCRRX1xtYXRocm17ZXF1aX0gPSBcZnJhY3tcc3FydHtTX299fXtufSBBXDsgUl57Mi8zfSQkIHdoZXJlDQoNCi0gICAkU19vJDogYm90dG9tIHNsb3BlIChhcyBjYWxjdWxhdGVkIGFib3ZlKQ0KDQotICAgJG4kOiBNYW5uaW5nIGNvZWZmaWNpZW50OiB0aGUgaGlnaGVyIHRoaXMgbnVtYmVyLCB0aGUgbW9yZSBmcmljdGlvbiwgdHlwaWNhbCB2YWx1ZXMgYXJlIGFyb3VuZCAwLjA0LCBidXQgZGlmZmljdWx0IHRvIGFzc2Vzcw0KDQotICAgJEEkOiB0aGUgd2V0dGVkIGNyb3NzIHNlY3Rpb24sIGFzIGRpc2N1c3NlZCBhbmQgY2FsY3VsYXRlZCBhYm92ZQ0KDQotICAgJFIkOiBoeWRyYXVsaWMgcmFkaXVzLiBGb3JtYWxseSBkZWZpbmVkIGFzIHdldHRlZCBBcmVhIGRpdmlkZWQgYnkgdGhlIHdldHRlZCBwZXJpbWV0ZXIoJFI9XGZyYWMge0F9e1B9JCksIGFzIGluIHRoZSBuZXh0IGNodW5rOg0KDQoNCg0KYGBge3IsIGV2YWw9VFJVRX0NCkhSLm4gPSAwLjA0NSANCg0KSFIuUiA9IGZ1bmN0aW9uKGEpDQp7DQogIHJldHVybigoSFIuYiphK0hSLm0qYV4yKS8oSFIuYisyKnNxcnQoMStIUi5tXjIpKmEpKQ0KfQ0KSFIuUWVxdWkgPSBmdW5jdGlvbihhKQ0Kew0KICBSID0gSFIuUihhKQ0KICBBID0gSFIuQShhKQ0KICBRID0gc3FydChIUi5TbykvSFIubipBKlJeKDIvMykgIyUgPQ0KICByZXR1cm4oc3FydChIUi5TbykvSFIubipBKlJeKDIvMykpDQp9DQoNClFlcXVpcmFuZ2UgPSBIUi5RZXF1aShhcmFuZ2UpDQpwbG90KFFlcXVpcmFuZ2UsYXJhbmdlLA0KICAgICBtYWluPSJIb29nZSBSYWFtIFEtYSBlcXVpbGlicml1bSIsDQogICAgIHhsYWI9IlFlcXVpIix5bGFiPSJhIixsd2Q9Myxjb2w9ImJsdWUiLHR5cGU9ImwiKQ0KZ3JpZChjb2w9ImJsYWNrIikNCmBgYA0KDQpTb21ldGltZXMgdGhlIHF1ZXN0aW9uIGlzIHBvc2VkIHRoZSBvdGhlciB3YXkgYXJvdW5kLiBBc3N1bWUgdGhhdCBvbmUgd2FudHMgdG8gZHJhaW4gYSBjb25zdGFudCBpbnRlbnNpdHkgb2YgMTAgJG1tL2RheSQgb2YgYW4gYXJlYSBvZiB0aGUgc2l6ZSBvZiAzMCAka21eMiQgdGhyb3VnaCB0aGlzIHJpdmVyLg0KDQo8ZGl2IGNsYXNzPSJxdWVzdGlvbiI+DQpTdGVwMTogY2FsY3VsYXRlIHRoZSBkaXNjaGFyZ2UgdGhyb3VnaCB0aGUgcml2ZXIuDQoNCmBgYHtyIGV2YWw9VFJVRX0NCmFyZWEgPSAzMCAjIGttXjINCmFyZWEgPSBhcmVhICooMTAwMCleMiAjIG1eMg0KSSA9IDEwICMgbW0gL2RheQ0KSSA9IEkvKDEwMDAqMjQqMzYwMCkgIyBtL3MgIysgPSANClEgPSBJKmFyZWENCmBgYA0KPC9kaXY+DQoNCg0KDQpOb3cgd2Ugd2FudCB0byBjYWxjdWxhdGUgdGhlIHdhdGVyIGxldmVsIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGVxdWlsaWJyaXVtIGRpc2NoYXJnZSBqdXN0IGNhbGN1bGF0ZWQuIFdlIGNhbiB1c2UgdGhlIHBsb3QgbWFkZSBhYm92ZSwgb3Igd2UgY2FuIHVzZSB0aGUgZm9sbG93aW5nIGNodW5rIHRvIGZpbmQgdGhlIHdhdGVyIGxldmVsIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGNhbGN1bGF0ZWQgZGlzY2hhcmdlIHJhdGUuDQoNCmBgYHtyLCBldmFsPVRSVUV9DQojaW5zdGFsbC5wYWNrYWdlcygibmxlcXNsdiIpDQpsaWJyYXJ5KG5sZXFzbHYpDQp0b3NvbHZlID0gZnVuY3Rpb24oYSl7cmV0dXJuIChIUi5RZXF1aShhKS1RKX0NCmFlcXVpID0gbmxlcXNsdigxLHRvc29sdmUpJHgNCnByaW50KGFlcXVpKQ0KYGBgDQo8ZGl2IGNsYXNzPSJxdWVzdGlvbiI+DQpSZXBlYXQgdGhlIGNhbGN1bGF0aW9uIGFib3ZlIGZvciB0aGUgcmFpbmZhbGwgaW50ZW5zaXRpZXMgYmV0d2VlbiAwLjUgbW0vZGF5IGFuZCAxNSBtbS9kYXkgYW5kIG1ha2UgYSBwbG90IG9mIHRoZSB3YXRlciBkZXB0aHMgdnMgdGhlc2UgaW50ZW5zaXRpZXMuDQoNCmBgYHtyIGV2YWw9VFJVRX0NCklzID0gc2VxKDAuNSwxNSxsZW5ndGg9MTAwKQ0KYWVxdWlzID0gYygpDQpmb3IoIGkgaW4gMTpsZW5ndGgoSXMpKQ0Kew0KICBJID0gSXNbaV0vKDM2MDAqMjQqMTAwMCkNCiAgUSA9IEkqYXJlYSAgICAgICAgICAgICAgICANCiAgdG9zb2x2ZSA9IGZ1bmN0aW9uKGEpe3JldHVybiAoSFIuUWVxdWkoYSktUSl9DQogIGFlcXVpc1tpXSA9IG5sZXFzbHYoMSx0b3NvbHZlKSR4DQp9DQpwbG90KElzLGFlcXVpcyx0eXBlPSJsIixjb2w9ImJsdWUiLGx3ZD0zLCBtYWluPSJXYXRlciBEZXB0aCBmb3IgRGlmZmVyZW50IFJhaW4gSW50ZW5zaXRpZXMiLCB4bGFiID0gIlJhaW5mYWxsIGludGVuc2l0eSAobW0vZGF5KSIsIHlsYWIgPSAiU3RlYWR5IHN0YXRlIHdhdGVyIGxldmVsIChtKSIpDQpncmlkKGNvbD0iYmxhY2siKQ0KYGBgDQo8L2Rpdj4NCg0KDQoNCiMgVGhlIGRvd25zdHJlYW0gd2Vpcg0KDQojIyBHZW9tZXRyeSBvZiB0aGUgd2Vpcg0KDQpTZWUgdGhlIGZvbGxvd2luZyBncmFwaA0KDQpgYGB7ciwgZXZhbD1UUlVFfQ0KSFIud2Vpci53aWR0aCA9IDIuMjUgICNtIHdpZHRoIG9mIHRoZSB3ZWlyIGZsb29yIA0KSFIud2Vpci5jcmVzdCA9IDEgI20gYWJvdmUgYm90dG9tIHJpdmVyDQojIGRyYXcgd2VpciBpbiBjcm9zcyBzZWN0aW9uDQpwbG90KGMoLXJldih3aWR0aHJhbmdlLzIpLHdpZHRocmFuZ2UvMiksYyhyZXYoYXJhbmdlKSxhcmFuZ2UpLA0KICAgICB4bGFiPSJ5Iix5bGFiPSJhIixtYWluPSJjcm9zcyBzZWN0aW9uIix0eXBlPSJsIixsd2Q9NSxjb2w9ImJyb3duIikNCmxpbmVzKGMoLUhSLndlaXIud2lkdGgvMiwtSFIud2Vpci53aWR0aC8yLEhSLndlaXIud2lkdGgvMixIUi53ZWlyLndpZHRoLzIpLA0KICAgICAgYyhtYXgoYXJhbmdlKSxIUi53ZWlyLmNyZXN0LEhSLndlaXIuY3Jlc3QsbWF4KGFyYW5nZSkpDQogICAgICAsY29sPSJibHVlIixsd2Q9MykNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCBpbnNldD0uMDUsDQogICAgICAgYygicml2ZXIiLCJ3ZWlyIiksIGNvbD1jKCJicm93biIsImJsdWUiKSxsd2Q9Myxob3Jpej1GQUxTRSkNCmdyaWQoY29sPSJibGFjayIpDQoNCmBgYA0KDQojIyBXZWlyIFEtYSByZWxhdGlvbg0KDQpUaGUgYW1vdW50IG9mIHdhdGVyIGZsb3dpbmcgb3ZlciBhIHdlaXIgaXMgYSBmdW5jdGlvbiBvZiB0aGUgd2F0ZXIgaGVpZ2h0IGFib3ZlIHRoZSBjcmVzdC4gRm9yIGEgcmVjdGFuZ3VsYXIgd2VpciB0aGlzIGlzIGEgd2VsbCBrbm93biBmb3JtdWxhOiAkJFFfXG1hdGhybXt3ZWlyfSA9IDEuODNcOyBCX1xtYXRocm17d2Vpcn1cOyAoYS1jX1xtYXRocm17d2Vpcn0pXnszLzJ9JCQNCg0KPGRpdiBjbGFzcz0icXVlc3Rpb24iPg0KRmluaXNoIHRoZSBjb2RlIGJlbG93IHN1Y2ggdGhhdCB0aGUgZnVuY3Rpb24gY2FsY3VsYXRlcyBkaXNjaGFyZ2VzIGFjY29yZGluZyB0byB0aGUgZm9ybXVsYSBhYm92ZS4NCg0KYGBge3IsIGV2YWw9VFJVRX0NCkhSLndlaXJRID0gZnVuY3Rpb24oYSkNCnsNCiAgYVthPEhSLndlaXIuY3Jlc3RdID0gSFIud2Vpci5jcmVzdA0KICByZXR1cm4oMS44MypIUi53ZWlyLndpZHRoKihhLUhSLndlaXIuY3Jlc3QpXigzLzIpKQ0KfQ0KDQp3ZWlyUXJhbmdlID0gSFIud2VpclEoYXJhbmdlKQ0KDQojIyBNQUtFIFRIRSBQTE9UIE5JQ0VSIEJZIEFESlVTVElORyBYTElNIFlMSU0gQU5EIExFR0VORA0KDQpwbG90KFFlcXVpcmFuZ2UsYXJhbmdlLG1haW49IlFlcXVpICh3aXRob3V0IHdlaXIpIGFuZCBRd2VpciBmb3IgSG9vZ2VSYWFtIiwNCiAgICAgeGxhYj0iUWVxdWkiLHlsYWI9ImEiLGx3ZD0zLGNvbD0iYmx1ZSIsdHlwZT0ibCIsIHlsaW0gPSBjKDAsMS41KSkNCmxpbmVzKHdlaXJRcmFuZ2UsYXJhbmdlLGx3ZD0zLGNvbD0icmVkIikNCmxlZ2VuZCgiYm90dG9tcmlnaHQiLCBpbnNldD0uMDUsDQogICAgICAgYygiUWVxdWlyaXZlciIsIlF3ZWlyIiksIGNvbD1jKCJibHVlIiwicmVkIiksbHdkPTMsaG9yaXo9RkFMU0UpDQpncmlkKGNvbD0iYmxhY2siKQ0KYGBgDQo8L2Rpdj4NCg0KDQoNCiMgUm91Z2ggYmFja3dhdGVyIGFwcHJveGltYXRpb24NCg0KRm9yIGFueSBnaXZlbiBmaXhlZCBkaXNjaGFyZ2UgJFEkIHRoYXQgZ29lcyB0aHJvdWdoIHRoZSBIb29nZSBSYWFtLCB3ZSBjYW4gY2FsY3VsYXRlIHR3byB3YXRlciBsZXZlbHMgd2l0aCB0aGUgaW5mb3JtYXRpb24gYWJvdmU6DQoNCi0gICBhIHdhdGVyIGRlcHRoIGFuZCBsZXZlbCBhdCB0aGUgd2Vpcg0KDQotICAgYW4gZXF1aWxpYnJpdW0gd2F0ZXIgZGVwdGggYW5kIGxldmVsIGZhciB1cHN0cmVhbSBvZiB0aGUgd2Vpcg0KDQpJbiBiZXR3ZWVuIHRoZSB3YXRlciBsZXZlbHMgd2lsbCB2YXJ5IGJldHdlZW4gdGhlc2UgdHdvLiBIZXJlIHdlIGZpcnN0IGFyZSBnb2luZyB0byBjYWxjdWxhdGUgdGhlc2UgbGV2ZWxzIGFuZCB0aGVuIGp1c3QgYXMgYSBmaXJzdCByb3VnaCBhcHByb3hpbWF0aW9uIGludGVycG9sYXRlIGxpbmVhciBpbiBiZXR3ZWVuLg0KDQo8ZGl2IGNsYXNzPSJxdWVzdGlvbiI+DQpDYWxjdWxhdGUgZm9yIFE9MS4yIHRoZSB3YXRlciBkZXB0aCBhdCB0aGUgd2VpciBhbmQgdGhlIHdhdGVyIGRlcHRoIGF0IHRoZSB1cHN0cmVhbSBlbmQNCg0KYGBge3IsIGV2YWw9VFJVRX0NCmxpYnJhcnkobmxlcXNsdikNClEgPSAxLjINCiNXYXRlciBsZXZlbCBmYXIgdXBzdHJlYW0NCnRvc29sdmUgPSBmdW5jdGlvbihhKXtyZXR1cm4gKEhSLlFlcXVpKGEpLVEpfQ0KYWVxdWkgPSBubGVxc2x2KDEsdG9zb2x2ZSkkeA0KcHJpbnQoYWVxdWkpDQoNCiNXYXRlciBsZXZlbCBhdCB0aGUgd2Vpcg0KdG9zb2x2ZSA9IGZ1bmN0aW9uKGEpe3JldHVybiAoSFIud2VpclEoYSktUSl9DQphd2VpciA9IG5sZXFzbHYoMS4xLHRvc29sdmUpJHgNCnByaW50KGF3ZWlyKQ0KYGBgDQo8L2Rpdj4NCiAgDQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCk1ha2UgYSBmdW5jdGlvbiBmb3IgdGhlIHJvdWdoIGxpbmVhciBhcHByb3hpbWF0aW9uIGFuZCBwbG90IGl0DQoNCmBgYHtyLCBldmFsPVRSVUV9DQpIUi5id3JvdWdoID0gYXBwcm94ZnVuKEhSLmRvbWFpbiwNCiAgICAgICAgICAgICAgICAgICAgICAgYyhIUi5ib3RlbGV2LnVwc3RyZWFtK2FlcXVpLEhSLmJvdGVsZXYuZG93bnN0cmVhbSthd2VpcikscnVsZT0yKSAjJSBhZXF1aSAjJSBhd2Vpcg0KcGxvdChIUi5kb21haW4sSFIuYndyb3VnaChIUi5kb21haW4pLHlsaW09YyhIUi5ib3RlbGV2LmRvd25zdHJlYW0sSFIuYm90ZWxldi51cHN0cmVhbSthZXF1aSksDQogICAgIG1haW49cGFzdGUoInJvdWdoIGxldmVsIGFwcHJveCBmb3IgUT0iLFEpLA0KICAgICB4bGFiPSJsIChtKSIseWxhYj0iaCAobSkiLGNvbD0iYmx1ZSIsbHdkPTQsdHlwZT0ibCIpDQoNCmxpbmVzKEhSLmRvbWFpbixIUi56YihIUi5kb21haW4pLGNvbD0iYnJvd24iLGx3ZD00KQ0KDQojQWRkIGxlZ2VuZCwgYmx1ZSBpcyB3YXRlciBlbGV2YXRpb24gYW5kIGJyb3duIGlzIHJpdmVyIGJlZCBlbGV2YXRpb24NCmBgYA0KPC9kaXY+ICANCg0KDQoNCiMgU2V0dXAgb2YgYmFzZSBiYWNrd2F0ZXIgbW9kZWwNCg0KVGhlIHByZXZpb3VzIGJhY2t3YXRlciBhcHByb3hpbWF0aW9uIGlzIHRvbyByb3VnaC4gSW4gcmVhbGl0eSB0aGUgd2F0ZXIgbGV2ZWxzIHdpbGwgdmFyeSBub24tbGluZWFyIChidXQgc3RpbGwgdmVyeSBzbW9vdGhseSkuIEEgMUQgZmxvdyBtb2RlbCBoYXMgdG8gYmUgc2V0dXAgdG8gY2FsY3VsYXRlIHRoZXNlIGxldmVscy4gU28gdGhlIDFEIGZsb3cgbGlicmFyeSBuZWVkcyB0byBiZSBsb2FkZWQ6DQoNCmBgYHtyLCBldmFsPVRSVUV9DQpsaWJyYXJ5KEZWRkUxRCkNCmBgYA0KDQojIyBUaGUgY2hvaWNlIG9mIHN0YXRlDQoNCkZvciBhbGwga2luZCBvZiBsb2NhbCBjYWxjdWxhdGlvbnMgdGhlIHdhdGVyIGRlcHRoICRhJCBpcyB0aGUgbW9zdCBjb21tb24gY2hvaWNlLiBGb3Igbm9uLWxvY2FsIHByb2JsZW1zIGFzIHRoZSBjYWxjdWxhdGlvbiBvZiBhIGJhY2t3YXRlciBjdXJ2ZSwgdGhlICp3YXRlciBsZXZlbCogd2l0aCByZXNwZWN0IHRvIEFNU0wgKHRoZSAkaCQgaW4gdGhlIHBsb3QgYWJvdmUpIGlzIHRoZSBtb3N0IGNvbW1vbiBjaG9pY2UuIFRoZXNlIHR3byBxdWFudGl0aWVzIGFyZSBjb25uZWN0ZWQgdGhyb3VnaCB0aGUgcml2ZXIsIGJvdHRvbSBoZWlnaHQ6XA0KJCQNCiAgaCA9IHpfYih4KSthIA0KJCQNCg0KRm9yIHRoZSBIb29nZSBSYWFtLCBhIGZ1bmN0aW9uIGZvciB0aGUgYm90dG9tIHdhcyBhbHJlYWR5IGdpdmVuOiAqKkhSLnpiKiogKHNlZSBhYm92ZSkuIA0KDQoNCiMjIFRoZSBlcXVhdGlvbg0KPGRpdiBjbGFzcz0icXVlc3Rpb24iPg0KRmluaXNoIHRoZSBmdW5jdGlvbiBkZWZpbml0aW9uIGJlbG93OiAgDQoNCmBgYHtyIGV2YWwgPVRSVUV9DQpIUi5hID0gZnVuY3Rpb24oeCxoKQ0Kew0KICByZXR1cm4oaC1IUi56Yih4KSkgIw0KfQ0KYGBgDQo8L2Rpdj4gIA0KDQoNCg0KDQoNCg0KIyMgVGhlIGludGVybmFsIGZsdXggZnVuY3Rpb24NCg0KIyMjIFRoZSB0aGVvcnkNCg0KVGhlIG1vc3QgaW1wb3J0YW50IHN0ZXAgaW4gZGVmaW5pbmcgYSBmbG93IG1vZGVsIGlzIHRoZSBkZWZpbml0aW9uIG9mIHRoZSBpbnRlcm5hbCBmbHV4LiBUaGUgZGVmaW5pdGlvbiBmb2xsb3dzIGZyb20gdGhlIGVxdWF0aW9uIGFzIGdpdmVuIGF0IHRoZSBzdGFydCBvZiB0aGlzIGRvY3VtZW50Og0KDQokJA0KMCA9ICBTX28gLSBTX2YgLSBcZnJhY3tccGFydGlhbCBhfXtccGFydGlhbCB4fSANCiQkDQoNClRoZSBmb3JtdWxhIGZvciB0aGUgZnJpY3Rpb24gc2xvcGUsICRTX2YkLCByZXF1aXJlcyBub3cgYSBiaXQgbW9yZSBzb3BoaXN0aWNhdGlvbi4NCg0KVGhlIGZsb3cgY2FuIG5vdyBiZSB0byB0aGUgcmlnaHQgKCRRPjAkKSBvciB0byB0aGUgbGVmdCAoJFE8MCQpLiBBbHRob3VnaCBpbiB0aGUgZ2l2ZW4gc2l0dWF0aW9uIGFuZCB3aXRoIHRoZSBjdXJyZW50IGNob2ljZSBvZiBkb21haW4sIHRoZSBmbG93IHNob3VsZCBiZSB0byB0aGUgcmlnaHQgYW5kIHRodXMgcG9zaXRpdmUsIGl0IGNhbiBub3QgYmUgZXhjbHVkZWQgdGhhdCBkdXJpbmcgdGhlIG51bWVyaWNhbCBjYWxjdWxhdGlvbnMgaXQgbWF5IGJlIChsb2NhbGx5KSBkaWZmZXJlbnQuIFRoZSBmcmljdGlvbiBzbG9wZSBpcyB0ZWNobmljYWxseSBkZWZpbmVkIGFzIHRoZSBhbW91bnQgb2YgZW5lcmd5IGxvc3MgaWYgZ29pbmcgaW4gdGhlIHBvc2l0aXZlIHgtZGlyZWN0aW9uLg0KDQotICAgaWYgdGhlIGZsb3cgaXMgaW4gdGhlIHBvc2l0aXZlIHgtZGlyZWN0aW9uICgkUT4wJCksIHRoZWlyIHNob3VsZCBiZSBsb3NzIGluIHRoZSBwb3NpdGl2ZSB4LWRpcmVjdGlvbiwgc28gdGhlIGZyaWN0aW9uIHNsb3BlIHNob3VsZCBiZSBwb3NpdGl2ZQ0KLSAgIGlmIHRoZSBmbG93IGlzIGluIHRoZSBuZWdhdGl2ZSB4LWRpcmVjdGlvbiAoJFE8MCQpLCB0aGVpciBzaG91bGQgYmUgbG9zcyBpbiB0aGUgbmVnYXRpdmUgeC1kaXJlY3Rpb24sIHNvIHRoZSBmcmljdGlvbiBzbG9wZSBzaG91bGQgYmUgbmVnYXRpdmUNCg0KVGhlc2UgdHdvIGNhc2VzIGNhbiBiZSBjb21iaW5lZCBpbnRvIG9uZSBmb3JtdWxhOg0KDQokJA0KU19mID0gXG1hdGhybXtzaWdufShRKSBcZnJhY3tuXjJcOyBRXjJ9e0FeMlw7IFJeezQvM319IA0KJCQNCg0Kd2hlcmUgdGhlIHNpZ24gZnVuY3Rpb24gaXMgZGVmaW5lZCBhcyBpbiB0aGUgUi1sYW5ndWFnZS4NCg0KPGRpdiBjbGFzcz0icXVlc3Rpb24iPg0KVXNlIHRoZSBoZWxwIG9mIFIgdG8gZ2l2ZSBhIGRlZmluaXRpb24gb2YgdGhlIHNpZ24gZnVuY3Rpb24gYmVsb3c6DQo8L2Rpdj4NCg0KDQoNClVzaW5nIHRoaXMgcmVzdWx0LCB0aGUgc2ltcGxpZmllZCBTdC1WZW5hbnQgY2FuIGJlIHdyaXR0ZW4gYXM6DQoNCiQkDQogXG1hdGhybXtzaWdufShRKSBcOyANCiBcZnJhY3tuXjJcOyBRXjJ9e0FeMlw7IFJeezQvM319ID0gU19mID0gU19vIC0gXGZyYWN7XHBhcnRpYWwgYX17XHBhcnRpYWwgeH0gID0gDQogLVxmcmFje1xwYXJ0aWFsIHpfYn17XHBhcnRpYWwgeH0gLSBcZnJhY3tccGFydGlhbCBhfXtccGFydGlhbCB4fSA9IA0KIC1cZnJhY3tccGFydGlhbCBofXtccGFydGlhbCB4fQ0KJCQNCg0KUmV3cml0aW5nIHRoaXMgZ2l2ZXM6ICQkUSAgPSAtXGZyYWN7MX17bn1cOyBcbWF0aHJte3NpZ259XEJpZyhcZnJhY3tccGFydGlhbCBofXtccGFydGlhbCB4fVxCaWcpXDsgXHNxcnR7IFxCaWd8IFxmcmFje1xwYXJ0aWFsIGh9e1xwYXJ0aWFsIHh9IFxCaWd8fVw7IEFcOyBSXnsyLzN9JCQNCg0KQXMgeW91IGNhbiBzZWUsIHRoZSBjaG9pY2Ugb2YgJGgkIGFzIHN0YXRlIGlzIGNvbnZlbmllbnQgaGVyZS4NCg0KIyMjIFRoZSBjb2RlDQoNCmBgYHtyLCBldmFsPVRSVUV9DQpIUi5RPSBmdW5jdGlvbih4LHN0YXRlLGdyYWRzdGF0ZSkNCnsNCiAgYSA9IEhSLmEoeCxzdGF0ZSkNCiAgUiA9IEhSLlIoYSkNCiAgQSA9IEhSLkEoYSkNCiAgcmV0dXJuKC0xL0hSLm4qc2lnbihncmFkc3RhdGUpKnNxcnQoYWJzKGdyYWRzdGF0ZSkpKkEqUl4oMi8zKSkgIysgKA0KfQ0KYGBgDQoNCg0KIyMgTW9kZWwgMTogdGhlIEhvb2dlIFJhYW0gYmFzZSBtb2RlbA0KDQpgYGB7ciwgZXZhbD1UUlVFfQ0KSFIuYmFja3dhdGVybW9kZWwgPSBuZXdGTE9XMUQoZG9tYWluPUhSLmRvbWFpbixzeXN0ZW1mbHV4ZnVuY3Rpb24gPSBIUi5RLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICdIb29nZSBSYWFtIGJhY2t3YXRlcicpDQoNCkhSLndlaXIuQkMgPSBmdW5jdGlvbihzdGF0ZSkNCnsNCiAgcmV0dXJuKC1IUi53ZWlyUShIUi5hKEhSLmxlbmd0aCxzdGF0ZSkpKQ0KfQ0KSFIuUWluID0gMS4yDQpzZXQuQkMuZmx1eHN0YXRlKEhSLmJhY2t3YXRlcm1vZGVsLCJyaWdodCIsSFIud2Vpci5CQykNCnNldC5CQy5maXhlZGZsdXgoSFIuYmFja3dhdGVybW9kZWwsd2hlcmU9ImxlZnQiLCJIUi5RaW4iKQ0Kc2V0LmRpc2NyZXRpc2F0aW9uKEhSLmJhY2t3YXRlcm1vZGVsLG5vZGVzPXNlcSgwLEhSLmxlbmd0aCxsZW5ndGg9NTApLG1ldGhvZD0nRkUnKQ0KDQpkby5pbml0aWFsaXplKEhSLmJhY2t3YXRlcm1vZGVsLEhSLmJ3cm91Z2gpDQoNCkhSLmFib3ZlYm90dG9tID0gZnVuY3Rpb24oeCxzdGF0ZSkNCnsNCiAgcmV0dXJuKEhSLmEoeCxzdGF0ZSk+MC4xKQ0KfQ0KDQpzZXQuaXNhY2NlcHRhYmxlKEhSLmJhY2t3YXRlcm1vZGVsLEhSLmFib3ZlYm90dG9tKQ0KYGBgDQoNCkRpc2N1c3M6DQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCi0gICBUaGUgbWludXMgc2lnbiBpbiB0aGUgZGVmaW5pdGlvbiBvZiB0aGUgbG93ZXIgYm91bmRhcnkgY29uZGl0aW9uOg0KPC9kaXY+DQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCi0gICB1c2UgdGhlIGhlbHAgb2YgRlZGRTFEIHRvIGRpc2N1c3MgdGhlIHJvbGUgb2YgdGhlIGRvdWJsZSBxdW90ZXMgYXJvdW5kIEhSLlFpbiBpbiB0aGUgZGVmaW5pdGlvbiBvZiB0aGUgdXBzdHJlYW0gYm91bmRhcnkgY29uZGl0aW9uOg0KPC9kaXY+DQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCi0gICBkZXNjcmliZSB0aGUgYWNjZXB0YWJpbGl0eSBjb25kaXRpb24gb2YgdGhlIG1vZGVsIGZvciB0aGUgbGV2ZWwgaW4gd29yZHM6DQo8L2Rpdj4gICAgDQoNCg0KYGBge3IsIGV2YWw9VFJVRX0NCnNvbHZlLnN0ZXBzKEhSLmJhY2t3YXRlcm1vZGVsKQ0KcGxvdChIUi5iYWNrd2F0ZXJtb2RlbCxmbHV4cGxvdD1UUlVFKQ0KYGBgDQoNCkFuZCBhIG5pY2UgcGxvdCB0byBjb21wYXJlIHRoZSByb3VnaCAobGluZWFyKSBhcHByb3hpbWF0aW9uIHdpdGggdGhlIHNtb290aCBvbmU6DQoNCmBgYHtyLCBldmFsPVRSVUV9DQpwbG90KEhSLmRvbWFpbixIUi5id3JvdWdoKEhSLmRvbWFpbikseWxpbT1jKEhSLmJvdGVsZXYuZG93bnN0cmVhbSxIUi5ib3RlbGV2LnVwc3RyZWFtK2FlcXVpKSwNCiAgICAgbWFpbj1wYXN0ZSgiQmFja3dhdGVyIGN1cnZlIGZvciBRPSIsSFIuUWluKSwNCiAgICAgeGxhYj0ibCAobSkiLHlsYWI9ImggKG0pIixjb2w9ImdyZWVuIixsdHk9Mixsd2Q9NCx0eXBlPSJsIikNCmxpbmVzKEhSLmRvbWFpbixIUi56YihIUi5kb21haW4pLGNvbD0iYnJvd24iLGx3ZD00KQ0KSFIuc3RhdGVzLjEgPSBkYXRhZnJhbWUuc3RhdGVzKEhSLmJhY2t3YXRlcm1vZGVsKQ0KbGluZXMoSFIuc3RhdGVzLjEsY29sPSJibHVlIixsd2Q9NCkNCmxlZ2VuZCgiYm90dG9tbGVmdCIsIGluc2V0PS4wNSwNCiAgICAgICBjKCJib3R0b20iLCJyYXcgYmFja3dhdGVyIiwidHJ1ZSBiYWNrd2F0ZXIiKSwgDQogICAgICAgY29sPWMoImJyb3duIiwiZ3JlZW4iLCJibHVlIiksbHR5PWMoMSwyLDEpLA0KICAgICAgIGx3ZD0zLGhvcml6PUZBTFNFKQ0KYGBgDQoNCiMjIE1vZGVsIDI6IGFkZGluZyBkcmFpbmFnZQ0KDQpBbGwgdGhlIGFwcHJvYWNoZXMgb25seSBjb25zaWRlcmVkIHRoZSBIb29nZSBSYWFtIGFzIGEgdHJhbnNwb3J0IHJpdmVyOiB3YXRlciBjb21pbmcgaW4gdXBzdHJlYW0gaGFkIHRvIGJlIHRyYW5zcG9ydGVkIGRvd25zdHJlYW0uIEluIHJlYWxpdHkgaW5wdXQgKGluIGRyYWluaW5nIHNpdHVhdGlvbnMpIG9mIHdhdGVyIGRvZXMgYWxzbyBvY2N1ciBhbG9uZyB0aGUgdHJhamVjdG9yeS4gVGhpcyBpcyBjYWxsZWQgKmxhdGVyYWwgaW5mbG93Ki4gSW4gdGVybXMgb2YgdGhlIEZWRkUxRCBwYWNrYWdlIHRoaXMgaXMgY2FsbGVkICpzcGF0aWFsZmx1eCouIEluIHRoaXMgZXhhbXBsZSB3ZSB3aWxsIHRoaW5rIG9mIHRoaXMgZmx1eCBjb21pbmcgZnJvbSBkcmFpbmluZyB0aGUgYXJhYmVsIGxhbmQgd2hlcmUgd2F0ZXIgY29sbGVjdGVkIGluIGRpdGNoZXMgYW5kIGRyYWluIHR1YmVzIGVuZGluZyB1cCBpbiB0aGUgcml2ZXIuIFdlIHdpbGwgdGhpbmsgb2YgdGhpcyBkcmFpbmFnZSBmbHV4IHRvIGJlIHVuaWZvcm0gb3ZlciB0aGUgbGVuZ3RoIG9mIHRoZSByaXZlci4gSW4gdGhpcyBjYXNlIHRoaXMgaXMgY2FsbGVkIEhSLmxhdGVyYWxkcmFpbmFnZS4gVGhlIG5hbWUgbGF0ZXJhbCBpcyBhIHR5cGljYWwgbmFtZSBmb3IgdGhpcyB0eXBlIG9mIGZsdXhlcyBpbiBvcGVuIHdhdGVyOiBsYXRlcmFsIG1lYW5zICJjb21pbmcgZnJvbSB0aGUgc2lkZSIsIHNvIGV4dGVybmFsLg0KDQpBIHByb3BlciB2YWx1ZSBmb3IgdGhpcyBudW1iZXIgc2hvdWxkIGNvbWUgZnJvbSBhIGdyb3VuZHdhdGVyIG1vZGVsLiBGb3IgYW4gZXhhbXBsZSB2YWx1ZSBoZXJlIHdlIGp1c3QgdGFrZSA1MCUgb2YgdGhlIGluZmxvdyB1cHN0cmVhbSBhcyBhIHRvdGFsLCB0aGF0IGhhcyB0byBiZSBkaXN0cmlidXRlZCBvdmVyIHRoZSBsZW5ndGggb2YgdGhlIHJpdmVyLg0KDQpgYGB7ciwgZXZhbD1UUlVFfQ0KSFIubGF0ZXJhbGRyYWluYWdlID0gMC41KkhSLlFpbi9IUi5sZW5ndGgNCmFkZC5zcGF0aWFsZmx1eChIUi5iYWNrd2F0ZXJtb2RlbCxyYXRlPSJIUi5sYXRlcmFsZHJhaW5hZ2UiLG5hbWU9ImRyYWluYWdlIikNCg0Kc29sdmUuc3RlcHMoSFIuYmFja3dhdGVybW9kZWwsdmVyYm9zZWxldmVsID0gMSkNCkhSLnN0YXRlcy4yID0gZGF0YWZyYW1lLnN0YXRlcyhIUi5iYWNrd2F0ZXJtb2RlbCkNCm5vZGVzID0gSFIuc3RhdGVzLjIkeA0KDQpwbG90KG5vZGVzLEhSLnpiKG5vZGVzKSxjb2w9ImJyb3duIix0eXBlPSJsIixsd2Q9NCx5bGltPWMoOSwxNiksDQogICAgIHhsYWI9ImwiLHlsYWI9ImgiLG1haW49cGFzdGUoImJhY2t3YXRlciArIGxhdGVyYWwgZmxvdyBIb29nZSBSYWFtIikpDQpsaW5lcyhIUi5zdGF0ZXMuMSxjb2w9Im9yYW5nZSIsbHdkPTMpDQpsaW5lcyhIUi5zdGF0ZXMuMixjb2w9ImJsdWUiLGx3ZD0zKQ0KZ3JpZChjb2w9ImJsYWNrIikNCmxlZ2VuZCgiYm90dG9tbGVmdCIsIGluc2V0PS4wNSwNCiAgICAgICBsZWdlbmQ9Yygid2l0aG91dCBkcmFpbmFnZSIsIndpdGggZHJhaW5hZ2UiKSwgY29sPWMoIm9yYW5nZSIsImJsdWUiKSwNCiAgICAgICBsd2Q9Myxob3Jpej1GQUxTRSkNCmBgYA0KDQpUaGlzIGNvbmNsdWRlcyB0aGUgZmlyc3QgcGFydCBhbmQgcmVzdWx0cyBpbiB0aGUgYmFzaWMgb3BlbiB3YXRlciBtb2RlbCBzaW11bGF0aW5nIGZsb3cgaW4gdGhlIEhvb2dlIFJhYW0uICBGb3IgdGhlIGxhdGVyYWwgaW5mbG93IGR1ZSB0byBkcmFpbmFnZSBpbiB0aGUgc3Vycm91bmRpbmcgYXJlYSBvZiB0aGUgSG9vZ2UgUmFhbSB3ZSBjaG9zZSBhbiBhcmJpdHJhcnkgdmFsdWUuIFN0YXJ0aW5nIGZyb20gdGhlIG5leHQgcGFydCAoMiksIHdlIHdpbGwgY2FsY3VsYXRlZCB0aGlzIGRyYWluYWdlIGFuZCBhbHNvIHdpbGwgZGV0ZXJtaW5lIHRoZSBzdXJmYWNlIHJ1bm9mZiB3aGVuIGFwcGxpY2FibGUuDQoNCg0KIyBQQVJUIDIgVGhlIGdyb3VuZHdhdGVyIG1vZGVsDQoNCldlIHdpbGwgYXNzdW1lIGEgMUQgZ3JvdW5kd2F0ZXIgbW9kZWwgc2ltdWxhdGluZyBvbmUgc3BlY2lmaWMgcGFyY2VsLCBlbmNsb3NlZCBiZXR3ZWVuIHR3byBkaXRjaGVzIG9yIGRyYWlucywgd2l0aGluIHRoZSBkcmFpbmFnZSBhcmVhIG9mIHRoaXMgcGFydCBvZiB0aGUgSG9vZ2UgUmFhbS5cDQpUaGlzIG1vZGVsIHdpbGwgY2FsY3VsYXRlIGEgaGVhZCBkaXN0cmlidXRpb24gYmV0d2VlbiBib3RoIGRpdGNoZXMuIFRoZSBtb2RlbCBkZXRlcm1pbmVzIGhvdyBtdWNoIGRyYWluYWdlIGZyb20gdGhlIGdyb3VuZHdhdGVyIGFuZCBkaXNjaGFyZ2UgZnJvbSBzdXJmYWNlIHJ1bm9mZiAoZHVyaW5nIHN0b3JtIGV2ZW50cykgd2lsbCBiZSBhbGxvY2F0ZWQgdG8gdGhlIEhvb2dlIFJhYW0uIFRoaXMgbW9kZWwgbXVzdCBiZSBpbWFnaW5lZCB0byBiZSBwZXJwZW5kaWN1bGFyIHRvIHRoZSBIb29nZSBSYWFtIG9wZW4gd2F0ZXIgbW9kZWwuIE11bHRpcGx5aW5nIHRoaXMgbGVuZ3RoIG9mIHRoaXMgbW9kZWwgKGRpc3RhbmNlIGJldHdlZW4gdGhlIHR3byBkaXRjaGVzKSB3aXRoIGEgcmVwcmVzZW50YXRpdmUgJ3dpZHRoJyB0byBjb21lIHRvIHRoZSB0b3RhbCBkaXNjaGFyZ2VkIGFyZWEuDQoNCiMjIEJhc2ljIGdyb3VuZHdhdGVyIGVxdWF0aW9uDQoNClNpbmNlIHdlIHdpbGwgYXNzdW1lIGEgb25lIGRpbWVuc2lvbmFsIG1vZGVsIGFuZCBvbmx5IGhvcml6b250YWwgZmxvdyAoRHVwdWl0KSB0aGUgYmFzaWMgZmxvdyBlcXVhdGlvbiBpczoNCg0KJCQNClFfe2d3fSA9IC1rRF97Z3d9ICogXGZyYWMge1xwYXJ0aWFsIEh9e1xwYXJ0aWFsIHh9DQokJA0KDQojIyBSdW5vZmYgQ2F1Y2h5IHR5cGUgdG9wIGJvdW5kYXJ5IGNvbmRpdGlvbg0KDQoNCiQkDQpRX3tydW5vZmZ9PSBcZnJhY3tIIC0gSF97c3VyZmFjZX19e0Nfe3N1cmZhY2V9fQ0KJCQNCg0KIyMgRGltZW5zaW9ucyBhbmQgcGFyYW1ldGVycyBncm91bmR3YXRlciBtb2RlbA0KDQpUaGUgYXZlcmFnZSBkaXRjaCBkaXN0YW5jZSBpcyAxMjUgbSBhbmQgdGhlIHRyYW5zbWlzc2l2aXR5IGluIHRoaXMgYXJlYSBpcyBlc3RpbWF0ZWQgb24gMjggJG1eMi9kJCBiYXNlZCBvbiB0aGUgaHlkcmF1bGljIGNvbmR1Y3Rpdml0eSBvZiB0aGUgc29pbCBhbmQgdGhlIHRoaWNrbmVzcy4NCg0KVGhlIGF2ZXJhZ2UgZGl0Y2ggbGV2ZWwgaXMgZ2l2ZW4gYXMgdGhlIGF2ZXJhZ2Ugcml2ZXIgYm90dG9tIGxldmVsICsgMjAgJGNtJC4NCg0KVGhlIGVudHJhbmNlIHJlc2lzdGFuY2UsIGR1ZSB0byBzZWRpbWVudHMgYXQgdGhlIGJvdHRvbSBvZiB0aGUgZGl0Y2gsIGlzIDMgJGRheXMkLg0KDQpXaGVuIHN1cmZhY2UgcnVub2ZmIG9jY3VycywgdGhlIHN0YXRlIGV4Y2VlZHMgdGhlIHN1cmZhY2UgbGV2ZWwgb2YgMTYuMCAkbSQgQU1TTCwgYSB2ZXJ0aWNhbCByZXNpc3RhbmNlIG9mIHRoZSB1cHBlciBzb2lsIG9mIDIwIGRheXMgKFZlcmFuZGVyaW5nc3JhcHBvcnRhZ2UgTEhNIDMuMzAgMjAxNywgcGcgMjMpIGNhbiBiZSBhc3N1bWVkLg0KDQpUaGUgc3RhdGlvbmFyeSBzaXR1YXRpb24gaXMgYmFzZWQgb24gdGhlIGF2ZXJhZ2UgeWVhcmx5IHJlY2hhcmdlOyBhYm91dCAwLjggJG1tL2QkLiBGb3IgdGhlIHRyYW5zaWVudCBtb2RlbCBhIHNpdHVhdGlvbiBvZiBhIHN0b3JtIGV2ZW50IHdpdGggYSBtYXhpbXVtIHByZWNpcGl0YXRpb24gcmF0ZSBvZiAzNiAkbW0vaG91ciQgZHVyaW5nIG9uZSBob3VyLCB3aWxsIGJlIHVzZWQgYXMgZm9yY2luZy4gDQoNCiAgDQojIEJhc2ljIHNldHVwDQoNCiMjIFJlcXVpcmVkIGZ1bmN0aW9ucw0KDQo8ZGl2IGNsYXNzPSJxdWVzdGlvbiI+DQpGaW5pc2ggdGhlIGZ1bmN0aW9ucyBpbiB0aGUgY2h1bmNrIGJlbG93IChyZXBsYWNlIFhYWFgsIFlZWVkpDQoNCmBgYHtyIGV2YWwgPSBUUlVFfQ0KTCA9IDEyNSAjIGF2ZXJhZ2UgZGl0Y2ggZGlzdGFuY2UgaW4gbQ0KDQpIX2RyYWluYWdlID0gKEhSLmJvdGVsZXYudXBzdHJlYW0gKyBIUi5ib3RlbGV2LmRvd25zdHJlYW0pLzIgKyAwLjINCkdXLmtEID0gNyAqIDQgIyBtMi9kICNrID0gNyBtL2QgYW5kIEQgPSA1IG0vZA0KDQpQID0gMC4wMDA4ICNlc3RpbWF0ZWQgYXZlcmFnZSBwcmVjaXBpdGF0aW9uIG0vZA0KDQpIX3N1cmZhY2UgPSAxNi4wICNhdmVyYWdlIHN1cmZhY2UgbGV2ZWwgYXJlYSBtDQpDX3N1cmZhY2UgPSAyMCAjZCBzdXJmYWNlIHZlcnRpY2FsIHJlc2lzdGFuY2UNCkNfZGl0Y2ggPSAzICNkIGVudHJhbmNlIHJlc2lzdGFuY2Ugb2YgdGhlIGRpdGNoZXMNCg0KRGl0Y2guYmMgPSBmdW5jdGlvbihzdGF0ZSkNCnsNCiAgaWYoc3RhdGUgPiBIX2RyYWluYWdlKQ0KICB7DQogIHJldHVybigoSF9kcmFpbmFnZSAtIHN0YXRlKS9DX2RpdGNoKQ0KICB9DQogIGVsc2UNCiAgew0KICAgIHJldHVybigwKQ0KICB9DQp9DQoNClEuZ3cgPSBmdW5jdGlvbih4LHN0YXRlLGdyYWRzdGF0ZSkNCnsNCiAgcmV0dXJuKC1HVy5rRCAqIGdyYWRzdGF0ZSkNCn0NCg0KUS5zcmZjID0gZnVuY3Rpb24oeCxzdGF0ZSkNCnsNCiAgaWYoc3RhdGUgPiBIX3N1cmZhY2UpIA0KICB7DQogIHN1cmZhY2UucnVub2ZmID0gKHN0YXRlIC0gSF9zdXJmYWNlKS9DX3N1cmZhY2UNCiAgcmV0dXJuKC1zdXJmYWNlLnJ1bm9mZikNCiAgfQ0KICBlbHNlDQogIHsgIA0KICAgIHJldHVybigwKQ0KICB9DQp9DQpgYGANCjwvZGl2Pg0KDQoNCg0KIyMgQmFzaWMgbW9kZWwgDQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCkZpbmlzaCB0aGUgY29kZSBpbiB0aGUgY2h1bmsgYmVsb3cgKHJlcGxhY2UgWFhYWCkNCllvdSBtYXkgY2hvc2Ugd2hpY2ggdHlwZSBvZiBkaXNjcmV0aXNhdGlvbiB5b3Ugd2FudCB0byB1c2UgKEZFLCBGViBldGMuKQ0KDQpgYGB7ciBldmFsID0gVFJVRX0NCkdXLmRvbWFpbiA9IGMoMCxMKQ0KR1cubm9kZXMgPSBzZXEoR1cuZG9tYWluWzFdLEdXLmRvbWFpblsyXSxsZW5ndGgub3V0ID00MCkNCkdXLnN0YXQgPSBuZXdGTE9XMUQoZG9tYWluID0gR1cuZG9tYWluLHN5c3RlbWZsdXhmdW5jdGlvbiA9IFEuZ3csIG5hbWUgPSAiZ3JvdW5kd2F0ZXIgbW9kZWwiKQ0KYWRkLnNwYXRpYWxmbHV4KG1vZGVsID0gR1cuc3RhdCxyYXRlID0gIlAiLG5hbWUgPSAicHJlY2lwaXRhdGlvbiIgKQ0KYWRkLnNwYXRpYWxmbHV4KG1vZGVsID0gR1cuc3RhdCxyYXRlID0gUS5zcmZjLG5hbWUgPSAic3VyZmFjZV9ydW5vZmYiKQ0KDQpzZXQuZGlzY3JldGlzYXRpb24obW9kZWwgPSBHVy5zdGF0LEdXLm5vZGVzLG1ldGhvZCA9ICJGRSIpDQpzZXQuQkMuZmx1eHN0YXRlKG1vZGVsID0gR1cuc3RhdCx3aGVyZSA9ICJsZWZ0IixmdW5jID0gRGl0Y2guYmMpDQpzZXQuQkMuZmx1eHN0YXRlKG1vZGVsID0gR1cuc3RhdCwgd2hlcmUgPSAicmlnaHQiLGZ1bmMgPSBEaXRjaC5iYykNCg0KZG8uaW5pdGlhbGl6ZShtb2RlbCA9IEdXLnN0YXQsSF9zdXJmYWNlKQ0Kc3VtbWFyeShHVy5zdGF0KQ0Kc29sdmUuc3RlcHMoR1cuc3RhdCwgdmVyYm9zZWxldmVsID0gMSkNCnBsb3QoR1cuc3RhdCxmbHV4cGxvdD1UKQ0Kd2JhbCA9IGRhdGFmcmFtZS5iYWxhbmNlKEdXLnN0YXQpDQprbml0cjo6IGthYmxlKHdiYWwpICNjcmVhdGVzIGEgdGFibGUgaW4gdGhlIGh0bWwNCg0KYGBgDQo8L2Rpdj4NCg0KDQoNCg0KDQojIFRyYW5zaWVudCBzaW11bGF0aW9ucw0KDQpUaGUgd2F0ZXIgYmFsYW5jZSBmb3IgdGhlIHRyYW5zaWVudCBncm91bmR3YXRlciBtb2RlbCBjYW4gYmUgZ2l2ZW4gYXM6DQoNCiQkDQpRX3tzdG9yYWdlfT0gUV97aW50ZXJuYWx9ICsgUV97ZXh0ZXJuYWx9XFwNCiBTIFxmcmFje1xwYXJ0aWFsIEh9e1xwYXJ0aWFsIHR9ID0gXGZyYWMge1xwYXJ0aWFsfXtccGFydGlhbCB4fVxsZWZ0ICggLWtEIFxmcmFje1xwYXJ0aWFsIEh9e1xwYXJ0aWFsIHh9IFxyaWdodCApICsgXHN1bSBRX2kNCiQkDQoNClRoZSBJbnRlcm5hbCBhbmQgRXh0ZXJuYWwgZmx1eGVzIGFyZSBhbHJlYWR5IGltcGxlbWVudGVkIGFuZCBub3cgd2UgYXJlIGdvaW5nIHRvIGluY2x1ZGUgdGhlIHRyYW5zaWVudCBwYXJ0LCBzZWUgYWxzbyB0aGUgc2Vjb25kIGFzc2lnbm1lbnQgd2l0aCBGVkZFIGluIHdlZWsgdHdvLg0KDQpUaGUgc3RvcmFnZSBjb2VmZmljaWVudCBpcyBlc3RpbWF0ZWQgb24gNSUuIEZvciB0aGUgc3Rvcm0gZXZlbnRzLCB0aGUgdGltZSBzdGVwIGlzIHNldCB0byAxIGhvdXIgYW5kIHRoZSB0b3RhbCBzaW11bGF0aW9uIHRpbWUgaXMgMTAgZGF5cywgc3RhcnRpbmcgd2l0aCBhIHN0YXRpb25hcnkgc2l0dWF0aW9uLCBmb2xsb3dlZCBieSBhIHN0b3JtIGV2ZW50IG9mIGEgZ3JhZHVhbGx5IGluY3JlYXNpbmcgcHJlY2lwaXRhdGlvbiByYXRlIHRpbGwgMzYgbW0vaG91ciBhbmQgZ3JhZHVhbGx5IGRlY3JlYXNpbmcgYWdhaW4gZHVyaW5nIDI0IGhvdXJzLiAgDQoNCkEgdGltZSBsb29wIGlzIHJlcXVpcmVkIGZvciB0aGlzIHNpbXVsYXRpb24gc3RlcHBpbmcgdGhyb3VnaCB0aGUgaG91cmx5IHRpbWUgc3RlcHMuDQoNCkFsc28gdGhlIHByZXZpb3VzIHN0YXRlIChoZWFkKSBpcyByZXF1aXJlZCBhbmQgbmVlZCB0byBiZSBzdG9yZWQgdGVtcG9yYXJpbHkgdG8gZGV0ZXJtaW5lIHRoZSBzdG9yYWdlIGNoYW5nZS4gKipUaXA6KiogdXNlIHRoZSAnc3BlY2lmaWMnIGZ1bmN0aW9uIGluIHRoZSBGVkZFMUQgcGFja2FnZSBmb3IgZm9yIHRoaXMuDQoNCiMjIFN0b3JhZ2UgZnVuY3Rpb24NCg0KQSBuZXcgImV4dGVybmFsIiBmbHV4IGZvciB0aGUgc3RvcmFnZSBub3cgbmVlZCB0byBiZSBkZWZpbmVkOw0KDQpTaW5jZSB0aGUgdGltZSBkZXJpdmF0aXZlIGlzICRcZnJhY3tccGFydGlhbCBIfXtccGFydGlhbCB0fSBcYXBwcm94IFxmcmFjIHtIXnt0K1xEZWx0YSB0fS1IXnR9e1xEZWx0YSB0fSQgd2F0ZXIgaXMgc3RvcmVkLCBhbmQgbm90IGF2YWlsYWJsZSBmb3IgaW50ZXJuYWwgZmxvdywgd2hlbiB0aGUgbmV3IGhlYWQgaXMgaGlnaGVyIHRoYW4gdGhlIHByZXZpb3VzIGhlYWQuDQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCkZpbmlzaCB0aGUgUS5zdG8gZnVuY3Rpb24gKHJlcGxhY2UgWFhYWCwgWVlZWSkNCg0KYGBge3IgZXZhbCA9IFRSVUV9DQpvbGQuc3RhdGUgPSBzdGF0ZS5mdW4obW9kZWwgPSBHVy5zdGF0KSAjYSBGVU5DVElPTiAoISkgdG8gc2F2ZSB0aGUgcHJldmlvdXMgc3RhdGUgb2YgdGhlIG1vZGVsLCBzbyBIIGF0IHQ9IHQgdG8gY2FsY3VsYXRlIHRoZSBuZXcgSCBhdCB0ID0gdCArIGRlbHQudCAuDQpHVy5TID0gMC4wNQ0KUS5zdG8gPSBmdW5jdGlvbih4LHN0YXRlKQ0Kew0KICBTdG9yYWdlLmZsdXggPSAtIEdXLlMgKiAoc3RhdGUgLSBvbGQuc3RhdGUoeCkpL2RlbHQudA0KICByZXR1cm4oU3RvcmFnZS5mbHV4KQ0KfQ0KDQpgYGANCjwvZGl2Pg0KDQoNCg0KIyMgVHJhbnNpZW50IG1vZGVsDQoNClRoZSB0cmFuc2llbnQgbW9kZWwgaXMgdGhlIHNhbWUgYXMgdGhlIHN0YXRpb25hcnkgbW9kZWwgd2l0aCB0aGUgYWRkaXRpb24gb2YgdGhlIHN0b3JhZ2UgZmx1eC4NCg0KYGBge3IgZXZhbD1UUlVFfQ0KR1cudHJhbnMgPSBjb3B5Lm1vZGVsKEdXLnN0YXQpDQphZGQuc3BhdGlhbGZsdXgobW9kZWwgPSBHVy50cmFucyxyYXRlID0gUS5zdG8sbmFtZSA9ICJzdG9yYWdlIikNCnN1bW1hcnkoR1cudHJhbnMpDQpgYGANCg0KIyMgU3Rvcm0gZXZlbnQNCg0KVGhlIHN0b3JtIGV2ZW50IGlzIHNpbXVsYXRlZCB3aXRoaW4gb25lIGRheSAoMjQgaG91cnMpIHdpdGggYSBtYXggb2YgMzYwIG1tL2QgZHVyaW5nIG9uZSBob3VyIGhhbGYgd2F5IHRoaXMgZGF5Lg0KDQpgYGB7cn0NClAucGF0dGVybi5yYXRlID0gYygwLjAwMDgsMC4wMTUqMjQqKHNpbihwaSpyZXAoMS8yNCooMToyNCkpKSksMC4wMDA4KQ0KUC5wYXR0ZXJuLmRhdGUgPSBjKDAscmVwKDEvMjQqKDE6MjQpKSwoMSsxLzI0KSkNClAucGF0dGVybiA9IGFwcHJveGZ1bihQLnBhdHRlcm4uZGF0ZSxQLnBhdHRlcm4ucmF0ZSxydWxlID0gMikNCnBsb3QoUC5wYXR0ZXJuLmRhdGUsUC5wYXR0ZXJuKFAucGF0dGVybi5kYXRlKSx0eXBlPSJsIixjb2wgPSAiYmx1ZSIsDQogICAgIGx3ZCA9IDIsIHhsYWIgPSAiZGF5cyIseWxhYiA9ICJpbnRpbnNpdHkgaW4gbS9kIixtYWluID0gIlN0b3JtIGV2ZW50IGluIG9uZSBkYXkiKQ0KZ3JpZCgpDQpgYGANCg0KIyMgVGltZSBsb29wDQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCkZpbmlzaCB0aGUgdGltZSBsb29wIHJlcGxhY2luZyBYWFhYLCBZWVlZLCBaWlpaIGFuZCBBQUFBLg0KDQpgYGB7ciBldmFsID0gVFJVRX0NCg0KI2RhdGEgY29udGFpbmVycyBmb3IgcmVzdWx0cw0KR1cuUS50cmFucyA9IGMoKQ0KR1cuSC50cmFucyA9IGMoKQ0KDQojdXNpbmcgdGhlIHN0YXRpb25hcnkgaGVhZCBvZiB0aGUgc3RhdGlvbmFyeSBtb2RlbCBmb3IgdGhlIGluaXRpYWwgaGVhZCBmb3IgdGhlIGZpcnN0IHRpbWUgc3RlcCBmb3IgdGhlIHRyYW5zaWVudCBtb2RlbA0Kb2xkLnN0YXRlID0gc3RhdGUuZnVuKEdXLnRyYW5zKSAjIGZpcnN0IGluaXRpYWwgb2xkIHN0YXRlIHRvIGJlIHVzZWQgaW4gdGhlIHdoaWxlIGxvb3AuDQoNCiN0aW1lIGFzcGVjdHMNCmRlbHQudCA9IDEvMjQgIyAxIGhvdXINCnN0YXJ0LnRpbWUgPSAwDQplbmQudGltZSA9ICAxMC4wICNkYXlzDQoNCmN1cnJlbnQudGltZSA9IHN0YXJ0LnRpbWUNCg0KI3RpbWUgbG9vcA0Kd2hpbGUgKGN1cnJlbnQudGltZSA8IGVuZC50aW1lKQ0Kew0KICBjdXJyZW50LnRpbWUgPSBjdXJyZW50LnRpbWUgKyBkZWx0LnQNCiAgUCA9IFAucGF0dGVybihjdXJyZW50LnRpbWUpICNwcmVjaXBpdGF0aW9uIGR1cmluZyB0aGUgc3Rvcm0gDQogIHNvbHZlLnN0ZXBzKEdXLnRyYW5zKQ0KICAjc2F2ZSBpbnRlcm1lZGlhdGUgZGF0YQ0KICB3YiA9IGRhdGFmcmFtZS5iYWxhbmNlKEdXLnRyYW5zKQ0KICBHVy5RLnRyYW5zID0gcmJpbmQoR1cuUS50cmFucywgYyhjdXJyZW50LnRpbWUsd2JbMiwzXSx3YlszLDJdLHdiWzMsM10sd2JbNCwyXSx3Yls1LDNdKSkNCiAgR1cuSC50cmFucyA9IHJiaW5kKEdXLkgudHJhbnMsIGRhdGFmcmFtZS5zdGF0ZXMoR1cudHJhbnMpWywyXSkNCiAgI3NhdmUgY3VycmVudCBzdGF0ZSBiZWluZyB0aGUgb2xkIHN0YXRlIGZvciB0aGUgbmV4dCB0aW1lIHN0ZXANCiAgb2xkLnN0YXRlID0gc3RhdGUuZnVuKEdXLnRyYW5zKQ0KfQ0KICAjc3RvcmluZyBhbmQgcGxvdHRpbmcgcmVzdWx0cw0KICBHVy5RLnRyYW5zID0gZGF0YS5mcmFtZShHVy5RLnRyYW5zKQ0KICBjb2xuYW1lcyhHVy5RLnRyYW5zKSA9IGMoInRpbWUiLCAic3VyZmFjZV9ydW5vZmYiLCJzdG9yYWdlXzJmbG93Iiwic3RvcmFnZV8yc3RvcmFnZSIsInByZWNpcCIsImJvdW5kYXJ5IikNCiAgDQogICNwbG90IHNvbWUgcmVzdWx0cw0KICBRLnJhbmdlID0gcmFuZ2UoR1cuUS50cmFucyRzdXJmYWNlX3J1bm9mZixHVy5RLnRyYW5zJHN0b3JhZ2VfMmZsb3csR1cuUS50cmFucyRzdG9yYWdlXzJzdG9yYWdlLEdXLlEudHJhbnMkcHJlY2lwLEdXLlEudHJhbnMkYm91bmRhcnkpDQogIHBsb3QoR1cuUS50cmFucyR0aW1lLEdXLlEudHJhbnMkc3VyZmFjZV9ydW5vZmYseWxpbSA9IFEucmFuZ2UsIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLGx3ZCA9MiwNCiAgICAgICB5bGFiID0gImZsdXggcmF0ZXMgaW4gbTIvZCIsIHhsYWIgPSAidGltZSBpbiBkYXlzIiwgbWFpbiA9ICJmbHV4IHJhdGVzIGdyb3VuZHdhdGVyIG1vZGVsIikNCiAgbGluZXMoR1cuUS50cmFucyR0aW1lLEdXLlEudHJhbnMkc3RvcmFnZV8yZmxvdyxjb2w9InllbGxvdzQiLGx3ZCA9IDIpDQogIGxpbmVzKEdXLlEudHJhbnMkdGltZSxHVy5RLnRyYW5zJHN0b3JhZ2VfMnN0b3JhZ2UsY29sPSJvcmFuZ2UiLGx3ZCA9IDIpDQogIGxpbmVzKEdXLlEudHJhbnMkdGltZSxHVy5RLnRyYW5zJHByZWNpcCxjb2w9ImJsdWUiLCBsd2QgPSAyKQ0KICBsaW5lcyhHVy5RLnRyYW5zJHRpbWUsR1cuUS50cmFucyRib3VuZGFyeSxjb2w9ImdyZWVuIikNCiAgbGVnZW5kKCJ0b3ByaWdodCIsIGluc2V0PS4wNSwNCiAgICAgICBsZWdlbmQ9YygicnVub2ZmIiwic3RvcmFnZV8yZmxvdyIsInN0b3JhZ2VfMnN0b3JhZ2UiLCJwcmVjaXBpdGF0aW9uIiwiZHJhaW5hZ2UiKSwgY29sPWMoInJlZCIsInllbGxvdzQiLCJvcmFuZ2UiLCJibHVlIiwiZ3JlZW4iKSwNCiAgICAgICBsd2Q9Myxob3Jpej1GQUxTRSkNCiNmaXJzdCAyIGRheXMgMioyNCA9IDQ4IHJvdw0KICANCiAgcGxvdChHVy5RLnRyYW5zJHRpbWVbMTo0OF0sR1cuUS50cmFucyRzdXJmYWNlX3J1bm9mZlsxOjQ4XSx5bGltID0gUS5yYW5nZSwgdHlwZSA9ICJvIiwgY29sID0gInJlZCIsbHdkID0yLA0KICAgICAgIHlsYWIgPSAiZmx1eCByYXRlcyBpbiBtMi9kIiwgeGxhYiA9ICJ0aW1lIGluIGRheXMiLCBtYWluID0gImZsdXggcmF0ZXMgZ3JvdW5kd2F0ZXIgbW9kZWwiKQ0KICBsaW5lcyhHVy5RLnRyYW5zJHRpbWVbMTo0OF0sR1cuUS50cmFucyRzdG9yYWdlXzJmbG93WzE6NDhdLGNvbD0ieWVsbG93NCIsbHdkID0gMikNCiAgbGluZXMoR1cuUS50cmFucyR0aW1lWzE6NDhdLEdXLlEudHJhbnMkc3RvcmFnZV8yc3RvcmFnZVsxOjQ4XSxjb2w9Im9yYW5nZSIsbHdkID0gMikNCiAgbGluZXMoR1cuUS50cmFucyR0aW1lWzE6NDhdLEdXLlEudHJhbnMkcHJlY2lwWzE6NDhdLGNvbD0iYmx1ZSIsIGx3ZCA9IDIpDQogIGxpbmVzKEdXLlEudHJhbnMkdGltZVsxOjQ4XSxHVy5RLnRyYW5zJGJvdW5kYXJ5WzE6NDhdLGNvbD0iZ3JlZW4iLCBsd2QgPSAyKQ0KICBsZWdlbmQoInRvcHJpZ2h0IiwgaW5zZXQ9LjA1LA0KICAgICAgIGxlZ2VuZD1jKCJydW5vZmYiLCJmbG93IG92ZXIgKHNhdHVyYXRlZClzdG9yYWdlIiwiZmxvdyB0byAodW5zYXR1cmF0ZWQpIHN0b3JhZ2UiLCJwcmVjaXBpdGF0aW9uIiwiZHJhaW5hZ2UiKSwgY29sPWMoInJlZCIsInllbGxvdzQiLCJvcmFuZ2UiLCJibHVlIiwiZ3JlZW4iKSwNCiAgICAgICBsd2Q9Myxob3Jpej1GQUxTRSkNCmdyaWQoKSAgDQoNCkdXLlEuZGF0YSA9IHN1bW1hcnkoR1cuUS50cmFucykgIA0Ka25pdHI6OmthYmxlKEdXLlEuZGF0YSwgY2FwdGlvbiA9ICJzdW1tYXJ5IGZsb3cgYnVkZ2V0IGdyb3VuZHdhdGVyIG1vZGVsIGluIG0yL2QiLCBmb3JtYXQgPSAic2ltcGxlIikNCmBgYA0KVGhlIHRlcm0gPGNvZGU+c3RvcmFnZV8yZmxvdzwvY29kZT4gc3RhbmRzIGZvciBzdG9yYWdlIHdoaWNoIGlzIHJlbGVhc2VkIHRvIGZsb3cgYW5kIDxjb2RlPnN0b3JhZ2VfMnN0b3JhZ2U8L2NvZGU+IGlzIHRoZSBhbW91bnQgb2Ygd2F0ZXIgd2hpY2ggd2lsbCBiZSBzdG9yZWQuDQo8L2Rpdj4NCg0KDQoNCg0KIyBQQVJUIDMgQ291cGxpbmcgb3BlbiB3YXRlciBhbmQgZ3JvdW5kd2F0ZXINCg0KQSAibG9vc2UiIGNvdXBsaW5nIHdpbGwgYmUgYXBwbGllZCBhbmQgYW5hbHl6ZWQuIFdpdGggdGhpcyB0aGUgb3BlbiB3YXRlciBtb2RlbCB3aWxsIHJlY2VpdmUgZHJhaW5hZ2UgYW5kIHN1cmZhY2UgcnVub2ZmIGZsdXhlcyBmcm9tIHRoZSBncm91bmR3YXRlciBtb2RlbC4gIA0KTGF0ZXIgb24sIG9uZSBtYXkgdXNlIHRoZSBjYWxjdWxhdGVkIG9wZW4gd2F0ZXIgbGV2ZWwgdG8gYWRqdXN0IHRoZSBkcmFpbiBkZXB0aCBpbiB0aGUgZ3JvdW5kd2F0ZXIgbW9kZWwgYWNoaWV2aW5nIGEgZnVsbCBjb3VwbGluZy4gVGhpcyB3aWxsIHJlc3VsdCBpbiBhIGZ1bGwgY291cGxpbmc6IGV4Y2hhbmdpbmcgZmx1eGVzIGZyb20gZ3JvdW5kd2F0ZXIgdG8gb3BlbiB3YXRlciBhbmQgZHJhaW4gZGVwdGggZnJvbSBvcGVuIHdhdGVyIHRvIGdyb3VuZHdhdGVyDQoNCg0KIyMjIFNjYWxpbmcgb2YgRHJhaW5hZ2UgYW5kIHN1cmZhY2UgcnVub2ZmDQoNClRoZSBwcmUtY2FsY3VsYXRlZCBkcmFpbmFnZSBhbmQgc3VyZmFjZSBydW5vZmYgb2YgdGhlIGdyb3VuZHdhdGVyIG1vZGVsIGFyZSB1c2VkIGFzIGlucHV0ICgiZm9yY2luZyIpIGZvciB0aGUgb3BlbiB3YXRlciBtb2RlbCBgSFIuYmFja3dhdGVybW9kZWxgIGFuZCBuZWVkIHRvIGJlICJzY2FsZWQiIHRvIHByb3BlciBkaW1lbnNpb25zOyAkbV4zL3MkLiAgXA0KVGhlIGdyb3VuZHdhdGVyIGRyYWluYWdlIGFuZCBzdXJmYWNlIHJ1bm9mZiBmbHV4ZXMgYXJlIGJhc2VkIG9uIG9uZSB0eXBpY2FsIHBhcmNlbCBoYXZpbmcgYW4gYXZlcmFnZSBkaXRjaCBkaXN0YW5jZSBvZiAxMjUgbS4gDQpUaGVyZSBhcmUgbWFueSBvZiB0aGVzZSBwYXJjZWxzIGluIHRoZSBjYXRjaG1lbnQgYXJlYSBvZiB0aGUgSG9vZ2UgUmFhbS4gVGhlc2UgZGlzY2hhcmdlIHJhdGVzIGhhdmUgdW5pdCAkbV4yL2QkIGFuZCBuZWVkIHRvIGJlIHRyYW5zZm9ybWVkIHRvIHRoZSB0b3RhbCBkaXNjaGFyZ2luZyBhcmVhIG9mIHRoZSBIb29nZSBSYWFtIGludG8gdW5pdHMgb2YgJG1eMy9zJC4gRm9yIHRoaXMsIHlvdSBjYW4gaW1hZ2luZSBhbGwgcGFyY2Vscywgd2l0aCBhbiBhdmVyYWdlIGRpdGNoIGRpc3RhbmNlIG9mIDEyNW0sIHdlcmUgc2V0IGJlaGluZCBlYWNoIG90aGVyIHJlc3VsdGluZyBpbiBhLCBsZXQncyBjYWxsIGl0IGEgKmRpZmZ1c2UgbGVuZ3RoKiBjYWxjdWxhdGVkIGFzOiAkXGZyYWMge1x0ZXh0e3RvdGFsX2RyYWluZWRfYXJlYX19e1x0ZXh0e2RpdGNoX2Rpc3RhbmNlfX0kLg0KVGhlIGZpZ3VyZSBiZWxvdyBpbGx1c3RyYXRlcyB0aGUgZGV0ZXJtaW5hdGlvbiBvZiB0aGUgdG90YWwgZGlmZnVzZSBsZW5ndGggPSAke1xzdW1cdGV4dHtMb2NhbFBhdGhMZW5ndGh9fT1cZnJhY3tcdGV4dHtEcmFpbmVkIEFyZWF9fXtcdGV4dHtEaXRjaCBEaXN0YW5jZX19JCAgXA0KIVtpbGx1c3RyYXRpb24gdG8gaW5kaWNhdGUgaG93IHRoZSBkaWZmdXNlIGxlbmd0aCBpcyBkZXRlcm1pbmVkXShIb29nZV9yYWFtX2RpZmZ1c2VfbGVuZ3RoLnBuZykNCiBcDQpGaW5hbGx5IHRoZSBncm91bmR3YXRlciBkcmFpbmFnZSBhbmQgc3VyZmFjZSBydW5vZmYgbmVlZCB0byBiZSB0cmFuc2Zvcm1lZCB0byBhIGxhdGVyYWwgaW5mbG93IHJhdGUgb2YgJG1eMy9zL21fe0hSY291cnNlfSQgZm9yIHRoZSBIb29nZSBSYWFtLlwNClRoZSB0b3RhbCBjb25zaWRlcmVkIGRpc2NoYXJnaW5nIGFyZWEgb2YgdGhlIEhvb2dlIFJhYW0gaXMgNTAwIGhhLiAgDQoNCg0KIA0KDQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCkRldGVybWluZSB0aGUgcHJvcGVybHkgc2NhbGVkIGRyYWluYWdlIGFuZCBydW5vZmYgZm9yIHRoZSBIb29nZSBSYWFtIG1vZGVsIDsgYEhSLmJhY2t3YXRlcm1vZGVsYC4NCmBgYHtyIGV2YWwgPSBUUlVFfQ0KIyMgZnJvbSBncm91bmR3YXRlciBkaXNjaGFyZ2UgdG8gbGF0ZXJhbCBpbmZsb3cgaW50byB0aGUgSG9vZ2UgUmFhbSBvcGVuIHdhdGVyIG1vZGVsDQpIUi5kaXNjaGFyZ2UuYXJlYSA9IDUwMCAqIDEwXjQjaW4gbTINCmRheTJzZWMgPSA4NjQwMCAjZnJvbSBkYXkgdG8gc2Vjb25kcw0KbTIuZGF5LnRvLm0zLmRheSA9ICAgSFIuZGlzY2hhcmdlLmFyZWEvTCAjZnJvbSBtMi9kYXkgdG8gbTMvZGF5OyBhICJkaWZmdXNlIGxlbmd0aCIgYmFzZWQgb24gdGhlIHRvdGFsIGRyYWluZWQgYXJlYSBkaXZpZGVkIGJ5IHRoZSBMKGRpdGNoIGRpc3RhbmNlKTsgdW5pdCBpcyBtIGJlY2F1c2UgaXQgaXMgdXNlZCB0byBjb252ZXJ0IG0yL2RheSB0byBtMy9kYXkNCg0KUS5kcmFpbmFnZS5tMy5kID0gR1cuUS50cmFucyRib3VuZGFyeSAqIG0yLmRheS50by5tMy5kYXkgIyBUb3RhbCBkcmFpbmFnZSBpbiB0aGUgY2F0Y2htZW50DQpRLmRyYWluYWdlLm0zLnMgPSBRLmRyYWluYWdlLm0zLmQvZGF5MnNlYyMgVG90YWwgZHJhaW5hZ2UgaW4gdGhlIGNhdGNobWVudA0KUS5kcmFpbmFnZS5tMi5zID0gUS5kcmFpbmFnZS5tMy5zL0hSLmxlbmd0aA0KICAjRHJhaW5hZ2UgcGVyIG0gcml2ZXINCg0KUS5ydW5vZmYubTMuZCA9IEdXLlEudHJhbnMkc3VyZmFjZV9ydW5vZmYgKiBtMi5kYXkudG8ubTMuZGF5ICMgVG90YWwgcnVub2ZmIGluIHRoZSBjYXRjaG1lbnQNClEucnVub2ZmLm0zLnMgPSBRLnJ1bm9mZi5tMy5kL2RheTJzZWMgIyBUb3RhbCBydW5vZmYgaW4gdGhlIGNhdGNobWVudA0KUS5ydW5vZmYubTIucyA9IFEucnVub2ZmLm0zLnMvSFIubGVuZ3RoICMgUnVub2ZmIHBlciBtIHJpdmVyDQoNCmBgYA0KPC9kaXY+DQoNCg0KDQo8ZGl2IGNsYXNzPSJxdWVzdGlvbiI+DQpDbG9zZWx5IGluc3BlY3QgdGhlIGZvbGxvd2luZyBjaHVuayBydW5uaW5nIHRoZSBvcGVuIHdhdGVyIG1vZGVsIGBIUi5iYWNrd2F0ZXJtb2RlbGAgd2l0aCBkcmFpbmFnZSBhbmQgc3VyZmFjZSBmbHV4ZXMgY29taW5nIGZyb20gdGhlIGdyb3VuZHdhdGVyIG1vZGVsLiAgDQo8L2Rpdj4NCg0KYGBge3IgZXZhbD0gVFJVRSwgYW5pbWF0aW9uMSwgIGZpZy5zaG93PSdhbmltYXRlJywgYW5pb3B0cz1jKCdjb250cm9scycsJ2xvb3AnKSwgaW50ZXJ2YWw9MC4xfQ0KDQojIyMjcHJlcGFyaW5nIG9wZW4gd2F0ZXIgbW9kZWwgZm9yIGRyYWluYWdlIGFuZCBzdXJmYWNlIHJ1bm9mZg0Kc3VtbWFyeShIUi5iYWNrd2F0ZXJtb2RlbCkNCnBsb3QoSFIuYmFja3dhdGVybW9kZWwsZmx1eHBsb3QgPSBUKQ0KDQojI3JlbW92aW5nIHRoZSBvbGQgbGF0ZXJhbCBmbHV4IGFuZCBhZGRpbmcgdGhlIG5ldyBkcmFpbmFnZSBhbmQgcnVub2ZmIGxhdGVyYWwgZmx1eGVzDQpyZW0uc3BhdGlhbGZsdXgoSFIuYmFja3dhdGVybW9kZWwsbmFtZSA9ICJkcmFpbmFnZSIpDQphZGQuc3BhdGlhbGZsdXgoSFIuYmFja3dhdGVybW9kZWwscmF0ZSA9ICJkcmFpbmFnZSIsbmFtZSA9ICJkcmFpbmFnZSIpDQphZGQuc3BhdGlhbGZsdXgoSFIuYmFja3dhdGVybW9kZWwscmF0ZSA9ICJydW5vZmYiLCBuYW1lID0gInJ1bm9mZiIpDQpzdW1tYXJ5KEhSLmJhY2t3YXRlcm1vZGVsKQ0KDQoNCiNkYXRhIGNvbnRhaW5lcnMgZm9yIHJlc3VsdHMNCkhSLlEudHJhbnMgPSBjKCkNCkhSLmgudHJhbnMgPSBjKCkNCkhSLlFfdXBzdHJlYW0gPSBjKCkNCkhSLlFfZG93bnN0cmVhbSA9IGMoKQ0KI2RhdGEgY29udGFpbmVyIGZvciByZXN1bHRzDQoNCiNwbG90IGZhY2lsaXR5DQpwbG90KG5vZGVzLEhSLnpiKG5vZGVzKSxjb2w9ImJyb3duIix0eXBlPSJsIixsd2Q9NCx5bGltPWMoMTEsMTgpLA0KICAgICB4bGFiPSJsIix5bGFiPSJoIixtYWluPXBhc3RlKCJUcmFuc2llbnQgd2F0ZXIgbGV2ZWxzIEhvb2dlIFJhYW0iKSkNCmxpbmVzKGRhdGFmcmFtZS5zdGF0ZXMoSFIuYmFja3dhdGVybW9kZWwpLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDMpDQpncmlkKCkNCg0KI2RlbHQudCA9IDEvMjQgY29tZXMgZnJvbSBncm91bmR3YXRlciBtb2RlbA0KY3VycmVudC50aW1lID0gMC4wDQojZW5kLnRpbWUgPSAyIGNvbWVzIGZyb20gZ3JvdW5kd2F0ZXIgbW9kZWwNCnRpbWUuc3RlcCA9IDANCg0KIyMjI3RpbWUgbG9vcCBmb3IgSFIuYmFja3dhdGVybW9kZWwgd2l0aCBmbHV4ZXMgZnJvbSB0aGUgZ3JvdW5kd2F0ZXIgbW9kZWwNCndoaWxlKGN1cnJlbnQudGltZSA8IGVuZC50aW1lKQ0KDQp7DQogIGN1cnJlbnQudGltZSA9IGN1cnJlbnQudGltZSArIGRlbHQudA0KICB0aW1lLnN0ZXAgPSB0aW1lLnN0ZXAgKyAxDQogIGRyYWluYWdlID0gUS5kcmFpbmFnZS5tMi5zW3RpbWUuc3RlcF0NCiAgcnVub2ZmID0gUS5ydW5vZmYubTIuc1t0aW1lLnN0ZXBdDQogIHNvbHZlLnN0ZXBzKEhSLmJhY2t3YXRlcm1vZGVsKQ0KICAjI3NhdmluZyBpbnRlcm1lZGlhdGUgcmVzdWx0cw0KICB3YiA9IGRhdGFmcmFtZS5iYWxhbmNlKEhSLmJhY2t3YXRlcm1vZGVsKQ0KICBIUi5RLnRyYW5zID0gcmJpbmQoSFIuUS50cmFucywgYyhjdXJyZW50LnRpbWUsd2JbNCwyXSx3YlszLDJdLHdiWzIsMl0sd2JbNCwzXSkpDQogIEhSLmgudHJhbnMgPSByYmluZChIUi5oLnRyYW5zLCBkYXRhZnJhbWUuc3RhdGVzKEhSLmJhY2t3YXRlcm1vZGVsKVssMl0pDQogIA0KICAjY3JlYXRlIHBsb3QgdG8gZ2VuZXJhdGUgYW4gYW5pbWF0aW9uIGluIHRoZSBrbml0dGVkIEhUTUwgZG9jdW1lbnQNCiAgcGxvdChub2RlcyxIUi56Yihub2RlcyksY29sPSJicm93biIsdHlwZT0ibCIsbHdkPTQseWxpbT1jKDExLDE4KSwNCiAgICAgICB4bGFiPSJsIix5bGFiPSJoIixtYWluPXBhc3RlKCJUcmFuc2llbnQgd2F0ZXIgbGV2ZWxzIEhvb2dlIFJhYW0iKSkNCiAgbGluZXMoZGF0YWZyYW1lLnN0YXRlcyhIUi5iYWNrd2F0ZXJtb2RlbCksIGNvbCA9ICJibHVlIiwgbHdkID0gMykNCiAgZ3JpZCgpDQogIA0KfQ0KICAjIyBjcmVhdGluZyBkYXRhIGZyYW1lcyBmb3IgdGhlIHJlc3VsdCBvZiB0aGUgb3BlbiB3YXRlciBtb2RlbCB3aXRoIGRyYWluYWdlIGFuZCBzdXJmYWNlIHJ1bm9mZiANCiBIUi5RLnRyYW5zID0gZGF0YS5mcmFtZShIUi5RLnRyYW5zKQ0KIGNvbG5hbWVzKEhSLlEudHJhbnMpID0gYygidGltZSIsImJvdW5kYXJ5X3Vwc3RyZWFtIiwicnVub2ZmIiwiZHJhaW5hZ2UiLCJib3VuZGFyeV9kb3duc3RyZWFtIikNCiBIUi5oLnRyYW5zID0gZGF0YS5mcmFtZShIUi5oLnRyYW5zKQ0KYGBgDQoNCiMjIyBDaGVja2luZyBmbHV4ZXMgYW5kIHRvdGFsIHZvbHVtZXMNCg0KRm9yIGJvdGggdGhlIHRyYW5zaWVudCBncm91bmR3YXRlciBhbmQgdGhlIHBzZXVkby1zdGF0aW9uYXJ5IG9wZW4gd2F0ZXIgbW9kZWwgdGhlIHRvdGFsIHZvbHVtZXMgb2Ygd2F0ZXIgKGluICRtXjMkKSBkdXJpbmcgdGhlIHNpbXVsYXRpb24gdGltZSBhcmUgY29tcGFyZWQgd2l0aCBib3RoIG1vZGVscy4NCg0KIyMjIyBncm91bmR3YXRlcg0KDQpWb2x1bWUgYmFsYW5jZSBmb3IgdGhlIGdyb3VuZHdhdGVyIG1vZGVsIA0KJCQNClRvdGFsX3tpbn0gPSBcc3VtX3t0PSAwfV57dD1UfVByZWNpcCh0KVxEZWx0YSB0XFwNClRvdGFsX3tvdXR9ID0gXGxlZnQgXHsgXHN1bV97dD0wfV57dD1UfSBRc3RvKHQpK1xzdW1fe3Q9MH1ee3Q9VH0gUnVub2ZmKHQpICsgXHN1bV97dD0wfV57dD1UfSBEcmFpbmFnZSh0KSBccmlnaHQgXH0gXERlbHRhIHQNCiQkDQpSZWNhbGwgdGhhdCB0aGUgd2F0ZXIgYmFsYW5jZSBvZiB0aGUgZ3JvdW5kd2F0ZXIgbW9kZWwgaXMgZXhwcmVzc2VkIGluICRtXjIvZCQuIFRvIGNvbWUgdG8gdm9sdW1lcyAoJG1eMyQpIG9uZSBuZWVkIHRvIGNvbnNpZGVyIHRoZSAiZGlmZnVzZSBsZW5ndGgiIGFuZCB0aGUgdGltZSBzdGVwLg0KDQpgYGB7ciBldmFsPVRSVUV9DQojIFdhdGVyIHZvbHVtZXMgZm9yIHRoZSAxRCBncm91bmR3YXRlciBtb2RlbCBkdXJpbmcgdGhlIHRvdGFsIHNpbXVsYXRpb24gdGltZQ0KDQpHVy52b2x1bWUuZHJhaW5hZ2UgPSBzdW0oR1cuUS50cmFucyRib3VuZGFyeSkgKiBtMi5kYXkudG8ubTMuZGF5ICogZGVsdC50DQpHVy52b2x1bWUucnVub2ZmID0gc3VtKEdXLlEudHJhbnMkc3VyZmFjZV9ydW5vZmYpICogbTIuZGF5LnRvLm0zLmRheSAqIGRlbHQudA0KDQpHVy52b2x1bWUuc3RvcmFnZV9pbnRvID0gc3VtKEdXLlEudHJhbnMkc3RvcmFnZV8yZmxvdykgKiBtMi5kYXkudG8ubTMuZGF5ICogZGVsdC50DQpHVy52b2x1bWUuc3RvcmFnZV9vdXRvZiA9IHN1bShHVy5RLnRyYW5zJHN0b3JhZ2VfMnN0b3JhZ2UpICogbTIuZGF5LnRvLm0zLmRheSAqIGRlbHQudA0KDQpHVy52b2x1bWUucHJlY2lwaXRhdGlvbiA9IHN1bShHVy5RLnRyYW5zJHByZWNpcCkgKiBtMi5kYXkudG8ubTMuZGF5ICogZGVsdC50DQoNCkdXLm1pc2ZpdCA9IEdXLnZvbHVtZS5wcmVjaXBpdGF0aW9uIC0gR1cudm9sdW1lLmRyYWluYWdlIC0gR1cudm9sdW1lLnJ1bm9mZiAtIEdXLnZvbHVtZS5zdG9yYWdlX291dG9mICsgR1cudm9sdW1lLnN0b3JhZ2VfaW50bw0KDQp2b2x1bWUuYmFsLkdXID0gZGF0YS5mcmFtZShHcm91bmR3YXRlciA9IGMoInByZWNpcGl0YXRpb24iLCJzdG9yYWdlXzJmbG93IiwiZHJhaW5hZ2UiLCJydW5vZmYiLCJzdG9yYWdlXzJzdG9yYWdlIiwidG90YWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIFZvbHVtZV9pbiA9IGMoR1cudm9sdW1lLnByZWNpcGl0YXRpb24sR1cudm9sdW1lLnN0b3JhZ2VfaW50bywwLDAsMCxzdW0oR1cudm9sdW1lLnByZWNpcGl0YXRpb24sR1cudm9sdW1lLnN0b3JhZ2VfaW50bykpLA0KICAgICAgICAgICAgICAgICAgICAgICAgVm9sdW1lX291dCA9IGMoMCwwLEdXLnZvbHVtZS5kcmFpbmFnZSxHVy52b2x1bWUucnVub2ZmLEdXLnZvbHVtZS5zdG9yYWdlX291dG9mLHN1bShHVy52b2x1bWUuZHJhaW5hZ2UsR1cudm9sdW1lLnJ1bm9mZixHVy52b2x1bWUuc3RvcmFnZV9vdXRvZikpKSMsDQogICAgICAgICAgICAgICAgICAgICAgICANCmtuaXRyOjprYWJsZSh2b2x1bWUuYmFsLkdXLGZvcm1hdCA9ICJzaW1wbGUiLCBjYXB0aW9uID0gIlRvdGFsIHZvbHVtZXMgaW4gbV4zIGdyb3VuZHdhdGVyIG1vZGVsIikNCg0KYGBgDQoNCiMjIyMgb3BlbiB3YXRlcg0KDQokJA0KVG90YWxfe2lufSA9IFxzdW1fe3Q9MH1ee3Q9VH0gYm91bmRhcnlfe3Vwc3RyZWFtfVxEZWx0YSB0ICsgXHN1bV97dD0wfV57dD1UfSBydW5vZmYgXERlbHRhIHQgKyBcc3VtX3t0PTB9Xnt0PVR9IGRyYWluYWdlIFxEZWx0YSB0XFwNClRvdGFsX3tvdXR9ID0gXHN1bV97dD0wfV57dD1UfSBib3VuZGFyeV97ZG93bnN0cmVhbX0NCiQkDQoNCmBgYHtyIGV2YWw9VFJVRX0NCiMgd2F0ZXIgdm9sdW1lcyBmb3IgdGhlIDFEIG9wZW4gd2F0ZXIgKEhvb2dlIFJhYW0pIG1vZGVsIGR1cmluZyB0aGUgdG90YWwgc2ltdWxhdGlvbiB0aW1lDQpIUi52b2x1bWUuYm5kLnVwc3RyZWFtID0gc3VtKEhSLlEudHJhbnMkYm91bmRhcnlfdXBzdHJlYW0pICogZGVsdC50ICogODY0MDAgI3VuaXQgZGVsdC50IGlzIGluIGRheXMhDQpIUi52b2x1bWUucnVub2ZmID0gc3VtKEhSLlEudHJhbnMkcnVub2ZmKSAqIGRlbHQudCAqIDg2NDAwDQpIUi52b2x1bWUuZHJhaW5hZ2UgPSBzdW0oSFIuUS50cmFucyRkcmFpbmFnZSkgKiBkZWx0LnQgKiA4NjQwMA0KSFIudm9sdW1lLmJuZC5kb3duc3RyZWFtID0gc3VtKEhSLlEudHJhbnMkYm91bmRhcnlfZG93bnN0cmVhbSkgKiBkZWx0LnQgKiA4NjQwMA0KDQpIUi52b2x1bWUuaW4gPSBIUi52b2x1bWUuYm5kLnVwc3RyZWFtICsgSFIudm9sdW1lLnJ1bm9mZiArIEhSLnZvbHVtZS5kcmFpbmFnZQ0KSFIudm9sdW1lLm91dCA9IEhSLnZvbHVtZS5ibmQuZG93bnN0cmVhbQ0KDQoNCiMjIHRoaXMgc2hvdWxkIGFkZCB1cCB0byB0aGUgdG90YWwgYW1vdW50IG9mIHByZWNpcGl0YXRpb24gZHVyaW5nIHRoZSBzaW11bGF0aW9uIHRpbWUuDQoNCnZvbHVtZS5iYWwuSFIgPSBkYXRhLmZyYW1lKE9wZW5fd2F0ZXIgPSBjKCJpbmZsb3dfdXBzdHJlYW0iLCJzdXJmYWNlX3J1bm9mZiIsImRyYWluYWdlIiwib3V0Zmxvd19kb3duc3RyZWFtIiwidG90YWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFZvbHVtZV9pbiA9IGMoSFIudm9sdW1lLmJuZC51cHN0cmVhbSxIUi52b2x1bWUucnVub2ZmLEhSLnZvbHVtZS5kcmFpbmFnZSwwLEhSLnZvbHVtZS5pbiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBWb2x1bWVfb3V0ID0gYygwLDAsMCxIUi52b2x1bWUuYm5kLmRvd25zdHJlYW0sSFIudm9sdW1lLm91dCkpDQprbml0cjo6a2FibGUodm9sdW1lLmJhbC5IUixmb3JtYXQuYXJnID0gbGlzdChkaWdpdHMgPSA4LG5zbWFsbCA9IDMpLCBjYXB0aW9uID0gIlRvdGFsIHZvbHVtZXMgaW4gbV4zIG9wZW4gd2F0ZXIgbW9kZWwiKSAjLGRpZ2l0cyA9IDE1KQ0KDQpgYGANCkNoZWNrIHdoZXRoZXIgdGhlIG91dHB1dCBvZiB0aGUgZ3JvdW5kd2F0ZXIgYXJlIHRoZSBzYW1lIGlucHV0cyBmb3IgdGhlIG9wZW4gd2F0ZXIgbW9kZWwuDQoNCiMjIFRpbWUgc2VyaWVzIGFuYWx5c2lzDQoNCkl0IGNhbiBiZSBpbnRlcmVzdGluZyB0byBmb3IgZXhhbXBsZSBjb21wYXJlIHRpbWUgc2VyaWVzIGZvciB0aGUgcHJlY2lwaXRhdGlvbiBhbmQgZGlzY2hhcmdlIG9mIHRoZSBIb29nZSBSYWFtLiBXaXRoIHRoaXMsIG9uZSBjYW4gZXhhbWluZSB0aGUgcmVzcG9uc2Ugb2YgYSBzdG9ybSBldmVudCBvbiB0aGUgb3BlbiB3YXRlciAtIGdyb3VuZHdhdGVyIHN5c3RlbS4NCg0KYGBge3IgZXZhbD1UUlVFfQ0KcGxvdChHVy5RLnRyYW5zJHRpbWUsIFAucGF0dGVybihHVy5RLnRyYW5zJHRpbWUpLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9MiwgeWxhYiA9ICJtL2QiLHhsYWIgPSAiZGF5cyIsdHlwZT0gImwiLCBtYWluID0gIlRyYW5zaWVudCBmbHV4ZXMgb3BlbiB3YXRlciBtb2RlbCBpbiBtL2QiLCBzdWIgPSAiVG90YWwgc2ltdWxhdGlvbiB0aW1lIikNCkhSLmRpc2NoYXJnZS5tLmQgPSBIUi5RLnRyYW5zJGJvdW5kYXJ5X2Rvd25zdHJlYW0gKiA4NjQwMCAvIEhSLmRpc2NoYXJnZS5hcmVhDQpsaW5lcyhIUi5RLnRyYW5zJHRpbWUsSFIuZGlzY2hhcmdlLm0uZCxjb2wgPSAicmVkIiwgbHdkID0yKQ0KSFIucnVub2ZmLm0uZCA9IEhSLlEudHJhbnMkcnVub2ZmICogODY0MDAgLyBIUi5kaXNjaGFyZ2UuYXJlYQ0KbGluZXMoSFIuUS50cmFucyR0aW1lLEhSLnJ1bm9mZi5tLmQsIGNvbCA9ICJicm93biIsbHdkID0gIDIpDQpIUi5kcmFpbmFnZS5tLmQgPSBIUi5RLnRyYW5zJGRyYWluYWdlICogODY0MDAgLyBIUi5kaXNjaGFyZ2UuYXJlYQ0KbGluZXMoSFIuUS50cmFucyR0aW1lLEhSLmRyYWluYWdlLm0uZCwgY29sID0gImdyZWVuIixsd2QgPTIpDQpncmlkKCkNCmxlZ2VuZCgidG9wcmlnaHQiLCBpbnNldD0uMDUsDQogICAgICAgbGVnZW5kPWMoInByZWNpcGl0YXRpb24iLCJIUiBkaXNjaGFyZ2UiLCJydW5vZmYiLCJkcmFpbmFnZSIpLCBjb2w9YygiYmx1ZSIsInJlZCIsImJyb3duIiwiZ3JlZW4iKSwNCiAgICAgICBsd2Q9Myxob3Jpej1GQUxTRSkNCg0KdGltZS5tYXgucHJlY2lwID0gd2hpY2gubWF4KFAucGF0dGVybihHVy5RLnRyYW5zJHRpbWUpKSpkZWx0LnQNCmFibGluZSh2PXRpbWUubWF4LnByZWNpcCwgY29sID0gImJsdWUiKQ0KDQp0aW1lLm1heC5kaXNjaGFyZ2UgPSB3aGljaC5tYXgoSFIuUS50cmFucyRib3VuZGFyeV9kb3duc3RyZWFtKSpkZWx0LnQNCnRpbWUubWF4LnJ1bm9mZiA9IHdoaWNoLm1heChIUi5RLnRyYW5zJHJ1bm9mZikqZGVsdC50DQp0aW1lLm1heC5kcmFpbmFnZSA9IHdoaWNoLm1heChIUi5RLnRyYW5zJGRyYWluYWdlKSpkZWx0LnQNCg0KYWJsaW5lKHY9dGltZS5tYXguZGlzY2hhcmdlLGNvbD0ncmVkJyxsd2Q9MykNCmFibGluZSh2PXRpbWUubWF4LmRyYWluYWdlLCBjb2wgPSAiZ3JlZW4iKQ0KDQpgYGANClpvb21pbmcgaW4gZm9yIHRoZSBmaXJzdCB0d28gZGF5cy4NCg0KYGBge3IgZXZhbD1UUlVFfQ0KcGxvdC50aW1lID0gR1cuUS50cmFucyR0aW1lWzE6NDhdDQpwbG90KHBsb3QudGltZSwgUC5wYXR0ZXJuKHBsb3QudGltZSksIGNvbCA9ICJibHVlIiwgbHdkID0yLCB5bGFiID0gIm0vZCIseGxhYiA9ICJkYXlzIix0eXBlPSAibyIsIG1haW4gPSAiVHJhbnNpZW50IGZsdXhlcyBvcGVuIHdhdGVyIG1vZGVsIGluIG0vZCIsIHN1YiA9ICJGaXJzdCB0d28gZGF5cyBzaW11bGF0aW9uIHRpbWUiKQ0KSFIuZGlzY2hhcmdlLm0uZCA9IEhSLlEudHJhbnMkYm91bmRhcnlfZG93bnN0cmVhbSAqIDg2NDAwIC8gSFIuZGlzY2hhcmdlLmFyZWENCmxpbmVzKEhSLlEudHJhbnMkdGltZSxIUi5kaXNjaGFyZ2UubS5kLGNvbCA9ICJyZWQiLCBsd2QgPTIpDQpIUi5ydW5vZmYubS5kID0gSFIuUS50cmFucyRydW5vZmYgKiA4NjQwMCAvIEhSLmRpc2NoYXJnZS5hcmVhDQpsaW5lcyhIUi5RLnRyYW5zJHRpbWUsSFIucnVub2ZmLm0uZCwgY29sID0gImJyb3duIixsd2QgPSAgMikNCkhSLmRyYWluYWdlLm0uZCA9IEhSLlEudHJhbnMkZHJhaW5hZ2UgKiA4NjQwMCAvIEhSLmRpc2NoYXJnZS5hcmVhDQpsaW5lcyhIUi5RLnRyYW5zJHRpbWUsSFIuZHJhaW5hZ2UubS5kLCBjb2wgPSAiZ3JlZW4iLGx3ZCA9MikNCmdyaWQoKQ0KbGVnZW5kKCJ0b3ByaWdodCIsIGluc2V0PS4wNSwNCiAgICAgICBsZWdlbmQ9YygicHJlY2lwaXRhdGlvbiIsIkhSIGRpc2NoYXJnZSIsInJ1bm9mZiIsImRyYWluYWdlIiksIGNvbD1jKCJibHVlIiwicmVkIiwiYnJvd24iLCJncmVlbiIpLA0KICAgICAgIGx3ZD0zLGhvcml6PUZBTFNFKQ0KDQp0aW1lLm1heC5wcmVjaXAgPSB3aGljaC5tYXgoUC5wYXR0ZXJuKHBsb3QudGltZSkpKmRlbHQudA0KYWJsaW5lKHY9dGltZS5tYXgucHJlY2lwLCBjb2wgPSAiYmx1ZSIpDQoNCnRpbWUubWF4LmRpc2NoYXJnZSA9IHdoaWNoLm1heChIUi5RLnRyYW5zJGJvdW5kYXJ5X2Rvd25zdHJlYW0pKmRlbHQudA0KdGltZS5tYXgucnVub2ZmID0gd2hpY2gubWF4KEhSLlEudHJhbnMkcnVub2ZmKSpkZWx0LnQNCnRpbWUubWF4LmRyYWluYWdlID0gd2hpY2gubWF4KEhSLlEudHJhbnMkZHJhaW5hZ2UpKmRlbHQudA0KDQphYmxpbmUodj10aW1lLm1heC5kaXNjaGFyZ2UsY29sPSdyZWQnLGx3ZD0xKQ0KYWJsaW5lKHY9dGltZS5tYXguZHJhaW5hZ2UsIGNvbCA9ICJncmVlbiIpDQpgYGANCg0KRnJvbSB0aGUgZ3JhcGhzIGl0J3MgY2xlYXJseSB2aXNpYmxlIHRoYXQgdGhlIGRpc2NoYXJnZSBpcyBkZWxheWVkIGNvbXBhcmVkIHRvIHRoZSBwcmVjaXBpdGF0aW9uLg0KVGhlIG1heC4gcHJlY2lwaXRhdGlvbiBpcyBhdCBkYXkgYHRpbWUubWF4LnByZWNpcGAgKGJsdWUgdmVydGljYWwgbGluZSkgYW5kIHRoZSBtYXguIGRpc2NoYXJnZSBpcyBhdCBkYXkgOiBgIHRpbWUubWF4LmRpc2NoYXJnZWAgKHJlZCB2ZXJ0aWNhbCBsaW5lKQ0KDQpUaGUgbW9tZW50IHdoZW4gdGhlIG1heGltdW0gZGlzY2hhcmdlIGF0IHRoZSB3ZWlyIG9mIHRoZSBIb29nZSBSYWFtIGlzIHJlYWNoZWQgY29pbmNpZGVzIHdpdGggdGhlIG1heC4gcnVub2ZmLg0KV2h5Pw0KQU5TV0VSOiBSdW5vZmYgYW5kIGRyYWluYWdlIGJvdGggY29tZSBmcm9tIHRoZSBzYW1lIDFEIGdyb3VuZHdhdGVyIG1vZGVsLiBTaW5jZSB0aGlzIG1vZGVsIGlzIDEgZGltZW5zaW9uYWwsIGZyb20gZGl0Y2ggdG8gZGl0Y2gsIGl0IGRvZXMgbm90IGNvbnRhaW4gYSBzcGF0aWFsIGRpc3RyaWJ1dGlvbiB3aXRoIHBhcmNlbCBmYXIgYXdheSBhbmQgY2xvc2UgYnkgdGhlIEhvb2dlIFJhYW0uIE1vcmVvdmVyIHRoZSAxRCB0cmFuc2llbnQgZ3JvdW5kd2F0ZXIgbW9kZWwgY2FsY3VsYXRlcyB0aGUgZWZmZWN0IG9mIHByZWNpcGl0YXRpb24gb24gZ3JvdW5kd2F0ZXIgc3RvcmFnZSwgZHJhaW5hZ2UgYW5kIHN1cmZhY2UgcnVub2ZmIGluIHRoZSBzYW1lIHRpbWUgc3RlcC4gSW4gb3RoZXIgd29yZHMsIHByZWNpcGl0YXRpb24gaXMgZGlzdHJpYnV0ZWQgb3ZlciB0aGVzZSB0aHJlZSBncm91bmR3YXRlciBzaW5rcyBpbiB0aGUgc2FtZSB0aW1lLg0KDQoNCg0KIyBQQVJUIDQgU2Vuc2l0aXZpdHkgYW5hbHlzaXMNCg0KSGVyZSB3ZSB3aWxsIGNvbnNpZGVyIHRoZSBsb2NhbCBzZW5zaXRpdml0eSBhbmFseXNpcy4NCg0KVGhlIHRhc2sgaXMgdG8gZGV0ZXJtaW5lIHdoYXQgdGhlIHVuY2VydGFpbnR5IG9mIGEgbW9kZWwgKGRlcml2ZWQpIHJlc3VsdCBpcyBkdWUgdG8gdGhlIHVzZWQgdGhlIHBhcmFtZXRlciB2YWx1ZXMgaW4gdGhlIG1vZGVsLg0KDQpGb3IgZXhhbXBsZTsgc3VwcG9zZSBvbmUgd2FudCdzIHRvIGRldGVybWluZSB0aGUgdW5jZXJ0YWludHkgb2YgdGhlIG1heCBoZWFkIGluIGEgZ3JvdW5kd2F0ZXIgbW9kZWwsIGR1ZSB0byB0aGUgbW9kZWwgcGFyYW1ldGVycyAobGlrZSBrRCwgYm91bmRhcnktY29uZGl0aW9ucywgcHJlY2lwaXRhdGlvbiwgZm9yIHdoaWNoIHlvdSBub3QgaGF2ZSBleGFjdCwgb3IgZ29vZCB2YWx1ZXMuDQoNCkZvciB0aGlzIHRoZSBmb2xsb3dpbmcgYXNwZWN0cyBuZWVkIHRvIGJlIGNvbnNpZGVyZWQvZGV0ZXJtaW5lZDoNCg0KMS4gIGRlcml2ZWQgcmVzdWx0LCBsaWtlIHRoZSBtYXggZGlzY2hhcmdlIChpbiB0aW1lKSBvZiB0aGUgSG9vZ2UgUmFhbQ0KDQoyLiAgbGlzdCBvZiBwYXJhbWV0ZXJzIGFuZCBpdCBvcHRpbWFsIChhc3N1bWVkKSB2YWx1ZXMNCg0KMy4gIGxpc3Qgb2YgdGhlIHNjYWxlIG9mIHZhcmlhdGlvbiBvZiB0aGUgcGFyYW1ldGVycw0KDQo0LiAgbG9jYWwgc2Vuc2l0aXZpdGllcyBmb3IgdGhlIHBhcmFtZXRlcnMNCg0KNS4gIHNjYWxlZCBjb250cmlidXRpb25zIHRvIHVuY2VydGFpbnR5IG9mIGVhY2ggcGFyYW1ldGVyDQoNCiMjIERlcml2ZWQgcmVzdWx0DQoNCmFsbCByZXN1bHRzIG9mIHRoZSBjdXJyZW50IGNvdXBsZWQgbW9kZWxzOg0KDQojIyMgZ3JvdW5kd2F0ZXIgbW9kZWw6DQoNCjEuICBoZWFkcywgJEgkLCBhdCBkaWZmZXJlbnQgdGltZSBzdGVwcyBhbmQgbG9jYXRpb25zDQoNCjIuICB3YXRlciBiYWxhbmNlIHRlcm1zKGZvciBkaWZmZXJlbnQgdGltZSBzdGVwcyBhbmQgbG9jYXRpb25zOg0KDQogICAgMS4gIGJvdW5kYXJ5IGluLCBib3VuZGFyeSBvdXQgKGRyYWluYWdlKQ0KDQogICAgMi4gIGludGVybmFsIGZsdXgNCg0KICAgIDMuICBzdG9yYWdlDQoNCiAgICA0LiAgcHJlY2lwaXRhdGlvbg0KDQogICAgNS4gIHN1cmZhY2UgcnVub2ZmDQoNClRoZSBtYXggZGlzY2hhcmdlIGlzIGBIUi5RLnRyYW5zJGJvdW5kYXJ5X2Rvd25zdHJlYW1bdGltZS5tYXguZGlzY2hhcmdlXWAgaW4gJG1eMy9zJCBhbmQgdGFrZXMgcGxhY2UgYXQgdGltZSA6IGBIUi5RLnRyYW5zJHRpbWVbdGltZS5tYXguZGlzY2hhcmdlXWAgZGF5cy4NCg0KDQojIyMgb3BlbiB3YXRlciBtb2RlbDoNCg0KMS4gIHdhdGVyIGxldmVscyBhdCBkaWZmZXJlbnQgdGltZSBzdGVwcyBhbmQgbG9jYXRpb25zDQoNCjIuICB3YXRlciBiYWxhbmNlIHRlcm1zIChmb3IgZGlmZmVyZW50IHRpbWUgc3RlcHMgYW5kIGxvY2F0aW9ucykNCg0KICAgIDEuICBpbmZsdXggdXBzdHJlYW0NCg0KICAgIDIuICBvdXRmbHV4IGRvd25zdHJlYW0NCg0KIyMgUGFyYW1ldGVyIGxpc3QNCg0KQWxsIHBhcmFtZXRlcnMgY2FuIGJlIHVzZWQgZm9yIGFuYWx5c2lzIG9mIHRoZSB1bmNlcnRhaW50eSBvZiB0aGUgbW9kZWwgcmVzdWx0LCBvZiAqKmJvdGgqKiwgbW9kZWxzLg0KDQojIyMgZ3JvdW5kd2F0ZXIgbW9kZWw6DQoNCjEuICBUcmFuc21pc3Npdml0eSBvZiB0aGUgc3Vic29pbCBgR1cua0RgDQoNCjIuICBFbnRyYW5jZSByZXNpc3RhbmNlIG9mIHRoZSBkaXRjaCBgQ19kaXRjaGANCg0KMy4gIEF2ZXJhZ2UgZHJhaW4gbGV2ZWwgb2YgdGhlIGFyZWEgYEhfZHJhaW5hZ2VgDQoNCjQuICBWZXJ0aWNhbCByZXNpc3RhbmNlIHRvcCBsYXllciBzb2lsIGBDX3N1cmZhY2VgDQoNCjUuICBBdmVyYWdlIHN1cmZhY2UgbGV2ZWwgZHJhaW5hZ2Ugc3lzdGVtIGBIX3N1cmZhY2VgDQoNCjYuICBTdG9yYWdlIGNvZWZmaWNpZW50OyBgR1cuU2ANCg0KIyMjIG9wZW4gd2F0ZXIgbW9kZWw6DQoNCjEuICB2YWx1ZSB3ZWlyIGNvbnN0YW50IChjdXJyZW50bHkgYDEuODNgKQ0KDQoyLiAgV2VpciBjcmVzdCBoZWlnaHQgYEhSLndlaXIuY3Jlc3RgDQoNCjMuICBXZWlyIHdpZHRoIGBIUi53ZWlyLndpZHRoYA0KDQo0LiAgTWFubmluZyBjb2VmZmljaWVudCBgSFIubmANCg0KNS4gIFJpdmVyIHdpZHRoIGBIUi5iYA0KDQo2LiAgU2lkZSBzbG9wZXMgYEhSLm1gDQoNCg0KIyMgU2NhbGUgb2YgdmFyaWF0aW9uICgkXHNpZ21hJCkNCg0KVGhlIHNjYWxlIG9mIHZhcmlhdGlvbiBjb3VsZCBiZSBiYXNlZCBvbiBsaXRlcmF0dXJlLCBmaWVsZCBleHBlcmltZW50cyBvciBmb3IgZXhhbXBsZSBvbiBhIG1vZGVsIGNhbGlicmF0aW9uLg0KDQojIyBDYWxjdWxhdGlvbiBsb2NhbCBzZW5zaXRpdml0aWVzDQoNCkFmdGVyIHdlIGhhdmUgZGV0ZXJtaW5lZCB0aGUgYmFzZSBtb2RlbCByZXN1bHQsIHdlIHdpbGwgZGV0ZXJtaW5lIHRoZSBsb2NhbCBzZW5zaXRpdml0eSBvZiB0aGUgYmFzZSByZXN1bHQgdy5yLnQuIHBhcmFtZXRlcjsgJFxmcmFje1xwYXJ0aWFsIE1vZGVsX3tyZXN1bHR9fXtccGFydGlhbCBQX2l9JC4NCg0KIyMgU2NhbGVkIGNvbnRyaWJ1dGlvbnMgdG8gcmVzdWx0IHVuY2VydGFpbnR5DQoNCg0KDQoNCg0KDQojIyBBU1NJR05NRU5UDQoNCkNhcnJ5IG91dCBhIGxvY2FsIHNlbnNpdGl2aXR5IGFuYWx5c2lzIGZvciBvbmUgb2YgdGhlIG1vZGVsIHJlc3VsdHMsIHRoZSBncm91bmR3YXRlciBhbmQgb3BlbiB3YXRlciBtb2RlbC4gIA0KDQoxLiAgQ2hvb3NlIGF0IGxlYXN0IDYgcGFyYW1ldGVycywgcHJlZmVyYWJseSBmcm9tIGJvdGggbW9kZWxzLCB0byBjYXJyeSBvdXQgdGhlIHNlbnNpdGl2aXR5IGFuYWx5c2lzIHdpdGgNCjIuICBFc3RpbWF0ZSB0aGUgc2NhbGUgb2YgdmFyaWF0aW9uIG9mIHRoZXNlIHBhcmFtZXRlcnMsIGJhc2VkIG9uIHlvdXIgZXhwZXJpZW5jZSwgd2hhdCB5b3UgaGF2ZSBoZWFyZCBkdXJpbmcgY291cnNlcyBvciBzaW1wbHkgZ29vZ2xlIGl0DQozLiAgQ3JlYXRlIGNodW5rcyB0byBkZXRlcm1pbmUgdGhlIGxvY2FsIHNlbnNpdGl2aXRpZXMNCjQuICBNYWtlIHVzZSBvZiB0aGUgcHJlLXByb2dyYW1tZWQgYHNlbnNpdGl2aXR5Lmxvb3AoKWAgZXhlY3V0aW5nIHRpbWUgbG9vcHMgZm9yIGVhY2ggbW9kZWwgYW5kIHNhdmluZyBpbnRlcm1lZGlhdGUgZGF0YQ0KNS4gIENyZWF0ZSBhIGNodW5rIHRvIGNhbGN1bGF0ZSB0aGUgZGVyaXZlZCB1bmNlcnRhaW50aWVzDQoNClRoaXMgPGNvZGU+c2Vuc2l0aXZpdHkubG9vcCgpPC9jb2RlPiBjb250YWlucyBtYW55IGxpbmVzIG9mIGNvZGUgYnV0IGJhc2ljYWxseSBkb2VzIHRoZSBmb2xsb3dpbmc6DQoNCjEuIFJ1biB0aGUgdHJhbnNpZW50IGdyb3VuZHdhdGVyIG1vZGVsIA0KMi4gU3RvcmUgcmVzdWx0cywgZmx1eCByYXRlcyAobTIvZCkgYW5kIGhlYWRzLCBvZiB0aGUgZ3JvdW5kd2F0ZXIgbW9kZWwgDQozLiBNdWx0aXBseSB0aGUgZHJhaW5hZ2UgYW5kIHJ1bm9mZiBmbHV4IHJhdGVzIHdpdGggdGhlIGRpZmZ1c2UgbGVuZ3RoIHRvIGNvbWUgdG8gbTMvZCBhbmQgdGhlbiB0byBtMy9zDQo0LiBSdW4gdGhlIHRyYW5zaWVudCBvcGVuIHdhdGVyIG1vZGVsIHdpdGggdGhlIGN1cnJlbnQgZHJhaW5hZ2UgYW5kIHJ1bm9mZiBmbHV4IHJhdGVzIA0KNS4gU3RvcmUgdGhlIG9wZW4gd2F0ZXIgZmx1eCByYXRlcyBhbmQgb3BlbiB3YXRlciBsZXZlbHMNCg0KDQpUbyBzZXQgdXAgYSBwcm9wZXIgcHJvY2VkdXJlLCBoYXZlIGNsb3NlIGxvb2sgYXQgdGhlIExvY2FsIFNlbnNpdGl2aXR5IEFuYWx5c2lzIGFzc2lnbm1lbnQgMSwgTG9jYWwgc2Vuc2l0aXZpdHkgMUQuDQoNCiMjIyBEZXJpdmVkIHVuY2VydGFpbnR5IHRvIGFuYWx5c2U7IHRoZSBgTVJFU1VMVCgpYA0KDQpGb3IgYSB3YXRlcmJvYXJkIGl0IGlzIGltcG9ydGFudCB0byBoYXZlIHNvbWUgaW5zaWdodCBpbiB0aGUgd2F5IHN0b3JtIGV2ZW50cyBhcmUgcHJvY2Vzc2VkIHdpdGhpbiB0aGUgYXJlYSB0aGV5IGNvbnRyb2wuIEl0IGlzIHRoZXJlZm9yIGltcG9ydGFudCB0aGF0IHRoZSB3YXRlciBtYW5hZ2VycyBjYW4gdGFrZSBtZWFzdXJlcyBiZWZvcmVoYW5kLCBsaWtlIGxvd2VyaW5nIHRoZSB3ZWlyIG9mIHRoZSBIb29nZSBSYWFtIGJlZm9yZSB0aGUgc3Rvcm0gZXZlbnQgYXJyaXZlcy4NCg0KSW4gdGhpcyBleGFtcGxlIHRoZSBkZXJpdmVkIHVuY2VydGFpbnR5IHdpbGwgYmUgdGhlIHRoZSBtYXguIHdlaXIgZGlzY2hhcmdlIChkb3duc3RyZWFtIG9mIHRoZSBIb29nZSBSYWFtKS4NCg0KVGhlcmUgYXJlIHNldmVyYWwgaW50ZXJlc3RpbmcgbW9kZWwgcmVzdWx0cyBmb3IgY2xvc2UgaW5zcGVjdGlvbiB3LnIudC4gdGhlaXIgJ2Rlcml2ZWQnIHVuY2VydGFpbnRpZXMuIFRvIGdpdmUgc29tZSBleGFtcGxlczoNCg0KKiAgTW9tZW50IHdoZW4gdGhlIHdhdGVyIGxldmVscyBvZiB0aGUgSG9vZ2UgUmFhbSByaXNlcyBmYXN0ZXN0DQoqICBUaGUgYnVmZmVyIGNhcGFjaXR5IG9mIHRoZSBhcmVhLCBlLmcuIHRoZSBtb21lbnQgd2hlbiBtb3N0IG9mIHRoZSBwcmVjaXBpdGF0aW9uIGlzIHN0b3JlZCBpbiB0aGUgZ3JvdW5kIA0KKiAgVGhlIG1heC4gd2F0ZXIgbGV2ZWwgaW4gdGhlIEhvb2dlIFJhYW0NCiogIEVmZmVjdCBvZiB0aGUgcHJlY2lwaXRhdGlvbiBkaXN0cmlidXRpb24gZHVyaW5nIGEgc3Rvcm0gZXZlbnQuDQoNCkFsbCByZXN1bHRzIGFyZSBzdG9yZWQgaW4gdGhlIGZvbGxvd2luZyAiY29udGFpbmVycyIgd2hpY2ggYXJlIGFsbCBzaW1wbGUgZGF0YSBmcmFtZS4gU2ltcGx5IGNsaWNrIG9uIHRoZW0gaW4gdGhlIHVwcGVyIHJpZ2h0IHBhbmVsIChFbnZpcm9ubWVudGFsIHRhYikgdG8gd2hhdCdzIGFsbCBzdG9yZWQ7DQoNCiogIGBHVy5RLnRyYW5zYCBmb3IgYWxsIGZsdXggcmF0ZXMgb2YgdGhlIGdyb3VuZHdhdGVyIG1vZGVsIGluIG0yL2Q7IGVhY2ggcm93IGlzIG9uZSB0aW1lIHN0ZXANCiogIGBHVy5ILnRyYW5zYCBmb3IgYWxsIGhlYWRzIGluIHRoZSBncm91bmR3YXRlciBtb2RlbDsgZWFjaCByb3cgaXMgb25lIHRpbWUgc3RlcCANCiogIGBIUi5RLnRyYW5zYCBmb3IgYWxsIGZsdXggcmF0ZXMgaW4gdGhlIG9wZW4gd2F0ZXIgbW9kZWwgaW4gbTMvczsgZWFjaCByb3cgaXMgb25lIHRpbWUgc3RlcCANCiogIGBIUi5ILnRyYW5zYCBmb3IgYWxsIGhlYWRzIGluIHRoZSBvcGVuIHdhdGVyIG1vZGVsOyBlYWNoIHJvdyBpcyBvbmUgdGltZSBzdGVwICANCg0KPGRpdiBjbGFzcz0icXVlc3Rpb24iPg0KQXMgYW4gZXhhbXBsZSwgYE1SRVNVTFQoKWAgaXMgdGhlIG1heC4gZGlzY2hhcmdlIG9mIHRoZSBIb29nZSBSYWFtIGF0IHRoZSB3ZWlyLiAgDQoNCmBgYHtyIGV2YWwgPSBUUlVFfQ0KTVJFU1VMVCA9IGZ1bmN0aW9uKCkNCnsNCiBtYXguZGlzY2hhcmdlPSBtYXgoSFIuUS50cmFucyRib3VuZGFyeV9kb3duc3RyZWFtKQ0KIHJldHVybihtYXguZGlzY2hhcmdlKQ0KfQ0KYGBgDQo8L2Rpdj4NCg0KQmUgYXdhcmUgdGhhdCBgTVJFU1VMVCgpYCBpcyBiYXNlZCBvbiB0aGUgcmVzdWx0cyB3aGljaCBhcmUgY29udGFpbmVkIGluIHRoZSAqKmN1cnJlbnQqKiBkYXRhIGZyYW1lcyBgR1cuUS50cmFucywgUVcuSC50cmFucywgSFIuUS50cmFucywgSFIuSC50cmFuc2AuIFRoZSBvcmlnaW5hbCB2YWx1ZSBvZiBgTVJFU1VMVCgpYCBpcyBhc3NpZ25lZCB0byBgTV9iYXNlYCwgaW4gdGhlIGNvZGUgY2h1bmsgb2YgdGhlIGZvbGxvd2luZyBzZWN0aW9uICJCYXNlIHJ1biIuDQoNCg0KDQojIyMgTW9kZWwgcGFyYW1ldGVycyAgDQoNCkFzIGFuIGV4YW1wbGUgdGhlIGZvbGxvd2luZyBtb2RlbCBwYXJhbWV0ZXJzIGNhbiBiZSB1c2VkIGZvciB0aGUgYW5hbHlzaXM7DQoNCjEuICBgSFIubmAgdGhlIG1hbm5pbmcgY29lZmZpY2llbnQNCjIuICBgQ19kaXRjaGAgdGhlIGVudHJhbmNlIHJlc2lzdGFuY2Ugb2YgdGhlIGRpdGNoZXMgaW4gdGhlIGFyZWENCjMuICBgSFIuUWluYCB0aGUgaW5mbHV4IGluICRtXjMvcyQgYXQgdGhlIHVwc3RyZWFtIGVuZCBvZiB0aGUgSG9vZ2UgUmFhbQ0KNC4gIGBIX3N1cmZhY2VgIHRoZSBhdmVyYWdlIGVsZXZhdGlvbiBvZiB0aGUgZHJhaW5lZCBhcmVhDQo1LiAgYEhfZHJhaW5hZ2VgIHRoZSBhdmVyYWdlIGRyYWluIGxldmVsIG9mIHRoZSBkcmFpbmVkIGFyZWENCjYuICBgR1cuU2Agc3RvcmFnZSBjb2VmZmljaWVudCBvZiB0aGUgc3Vic29pbCAocmVwbGFjZW1lbnQgb2YgNSkNCg0KPGRpdiBjbGFzcz0icXVlc3Rpb24iPg0KU2V0IHVwIHRoZSBiYXNlIGxpc3QgZm9yIHRoZSBhZm9yZW1lbnRpb25lZCBwYXJhbWV0ZXJzLiBZb3UgbWF5IGFsc28gY2hvb3NlIGRpZmZlcmVudCBwYXJhbWV0ZXJzIHJpZ2h0IGF3YXkuICANCmBgYHtyIGV2YWwgPSBUUlVFfQ0KYmFzZSA9IGxpc3QoR1cua0QgPSBHVy5rRCwgQ19kaXRjaCA9IENfZGl0Y2gpICMgdGhlIGxpc3Qgd2l0aCB0aGUgY3VycmVudCBtb2RlbCBwYXJhbWV0ZXJzDQpzdHIoYmFzZSkjIHByaW50IHRoZSBsaXN0IGZvciBpbnNwZWN0aW9uDQpgYGANCjwvZGl2Pg0KDQoNCg0KDQoNCiMjIyBTY2FsZSBvZiB2YXJpYXRpb24NCg0KPGRpdiBjbGFzcz0icXVlc3Rpb24iPg0KRXN0aW1hdGUgdGhlIHNjYWxlIG9mIHZhcmlhdG9uIGZvciB0aGUgbW9kZWwgcGFyYW1ldGVycy4gIA0KYGBge3IgZXZhbCA9IFRSVUV9DQpzY2FsZSA9IGxpc3QoR1cua0QgPSAwLjEqR1cua0QsIENfZGl0Y2ggPSAwLjEqQ19kaXRjaCkjbGlzdCBvZiB0aGUgc2NhbGUgb2YgdmFyaWF0aW9uIG9mIHRoZSBtb2RlbCBwYXJhbWV0ZXJzDQpzdHIoc2NhbGUpI3ByaW50IHRoZSBzY2FsZXMgZm9yIGluc3BlY3Rpb24NCmBgYA0KPC9kaXY+DQoNCg0KDQojIyMgQmFzZSBydW4NCg0KVG8gZGV0ZXJtaW5lIHRoZSBzZW5zaXRpdml0aWVzIHRoZSBiYXNlIGRhdGEgbmVlZCB0byBiZSBzYXZlZDsgIA0KYGBge3IgZXZhbD1UUlVFfQ0KTV9iYXNlID0gTVJFU1VMVCgpDQpwcmludChNX2Jhc2UpDQpHVy5zdGF0ZS5iYXNlID0gR1cuSC50cmFucyMgYSBkYXRhLmZyYW1lIGZvciB0aGUgaGVhZHMgcGVyIHRpbWUgc3RlcCBvZiB0aGUgZ3JvdW5kd2F0ZXIgbW9kZWwNCkdXLmZsdXguYmFzZSA9IEdXLlEudHJhbnMjIGEgZGF0YS5mcmFtZSBmb3IgdGhlIGZsdXhlcyBwZXIgdGltZSBzdGVwIG9mIHRoZSBncm91bmR3YXRlciBtb2RlbA0KSFIuc3RhdGUuYmFzZSA9IEhSLmgudHJhbnMjIGEgZGF0YS5mcmFtZSBmb3IgdGhlIHdhdGVyIGxldmVscyBvZiB0aGUgSG9vZ2UgUmFhbSBtb2RlbA0KSFIuZmx1eC5iYXNlID0gSFIuUS50cmFucyMgYSBkYXRhYS5mcmFtZSBmb3IgdGhlIGZsdXhlcyBwZXIgdGltZSBzdGVwIG9mIHRoZSBIb29nZSBSYWFtIG1vZGVsDQoNCmVwcyA9IDAuMDEgIzElIG9mIHRoZSBvcmlnaW5hbCB2YWx1ZSBob3BlZnVsbHkgYXZvaWRpbmcgcm91bmRpbmcgZXJyb3JzIGFuZCBzdGlsbCBiZSBpbiBkZSBwcm9wZXIgbG9jYWwgZG9tYWluLg0KYGBgDQoNCiMjIyBEZXRlcm1pbmUgbG9jYWwgcGFyYW1ldGVyIHNlbml0aXZpdGllcyANClRoZSBjaG9zZW4gcGFyYW1ldGVycyB3aWxsIGJlIGFsdGVyZWQgYnkgdGhlIGBlcHNgIHZhbHVlIGFuZCByZXNldCBhZnRlciB0aGUgcnVuLiAgDQpOZXh0IHRoZSBsb2NhbCBzZW5zaXRpdml0eSBvZiB0aGlzIHBhcmFtZXRlciAkUF9pJCB3LnIudC4gYE1SRVNVTFQoKWAgd2lsbCBiZSBkZXRlcm1pbmVkOyAkXGZyYWN7XHBhcnRpYWwgXHRleHR7TVJFU1VMVH19e1xwYXJ0aWFsIFBfaX0kLiAgDQoNCiMjIyMgVGhlIHNlbnNpdGl0eSBsb29wIGZ1bmN0aW9uDQpUbyBhdXRvbWF0ZSB0aGUgcHJvY2VkdXJlIHRvIGRldGVybWluZSB0aGUgbG9jYWwgc2Vuc2l0aXZpdGllcyB3ZSB3aWxsIG1ha2UgdXNlIG9mIGEgZnVuY3Rpb24gcnVubmluZyB0aGUgZ3JvdW5kd2F0ZXIgbW9kZWwgbG9vcCBhbmQgdGhlIG9wZW4gd2F0ZXIgbW9kZWwgbG9vcCBpbiBhIHNlcXVlbmNlOyB0aGUgYHNlbnNpdGl2aXR5Lmxvb3AoKWAgZnVuY3Rpb247DQoNCjxkaXYgY2xhc3M9InF1ZXN0aW9uIj4NCkNsb3NlbHkgaW5zcGVjdCB3aGF0IGlzIGNhcnJpZWQgb3V0IGR1cmluZyBvbmUgcGFzcyBvZiB0aGlzIGxvb3AuICANClByb2JhYmx5IG5vdCBhIHZlcnkgZmFtaWxpYXIgb3BlcmF0b3IgaW4gdGhpcyBsb29wIGlzIHRoZSBgPDwtYCBzeW1ib2wvb3BlcmF0b3IuIEl0IG1lYW5zIHRoYXQgZ2xvYmFsIGBQYCwgYGRyYWluYWdlYCwgYHJ1bm9mZmAsIGBHVy5RLnRyYW5zIEdXLkgudHJhbnMgSFIuUS50cmFucyBIUi5oLnRyYW5zYCBkYXRhLmZyYW1lcyBhbmQgdGhlIGBvbGQuc3RhdGVgIGZ1bmN0aW9uIGFyZSBhZGp1c3RlZCB3aXRoaW4gdGhpcyBmdW5jdGlvbiBhdm9pZGluZyBhIHZlcnkgbGFyZ2Ugc2V0IG9mIGFyZ3VtZW50cyB0byBwYXNzIHRvIHRoaXMgZnVuY3Rpb24uICANCjwvZGl2Pg0KDQpgYGB7cn0NClNlbnNpdGl2aXR5Lmxvb3AgPSBmdW5jdGlvbigpDQp7DQogICMgdGhlIGdyb3VuZHdhdGVyIG1vZGVsIGxvb3AsIEdXIG1vZGVsIGZpcnN0IGJlY2F1c2Ugd2UgdXNlIHRoZSBkcmFpbmFnZSBhbmQgcnVub2ZmIHRvIHRoZSBiYWNrd2F0ZXIgbW9kZWwsIGFmdGVyIHRoYXQgcnVuIGJhY2t3YXRlciBtb2RlbA0KICANCiAgI2RhdGEgY29udGFpbmVyIGZvciByZXN1bHRzDQogIEdXLlEudHJhbnMgPSBjKCkNCiAgR1cuSC50cmFucyA9IGMoKQ0KICB0ZW1wLnJ1bm9mZiA9IGMoKQ0KICANCg0KICAjdXNpbmcgdGhlIHN0YXRpb25hcnkgaGVhZCBmb3IgdGhlIGluaXRpYWwgaGVhZCBmb3IgdGhlIGZpcnN0IHRpbWUgc3RlcCBmb3IgdGhlIHRyYW5zaWVudCBtb2RlbA0KICBvbGQuc3RhdGUgPDwtIHN0YXRlLmZ1bihHVy5zdGF0KQ0KICANCiAgZGVsdC50ID0gMS8yNCAjIDEgaG91cg0KICBzdGFydC50aW1lID0gMA0KICBlbmQudGltZSA9ICAxMC4wDQogIA0KICBjdXJyZW50LnRpbWUgPSBzdGFydC50aW1lDQogIA0KICB3aGlsZSAoY3VycmVudC50aW1lIDwgZW5kLnRpbWUpDQogIHsNCiAgICAjdGltZSBzdGVwcGluZw0KICAgIGN1cnJlbnQudGltZSA9IGN1cnJlbnQudGltZSArIGRlbHQudA0KICAgIA0KICAgICNHcm91bmR3YXRlciBtb2RlbCBydW4NCiAgICBQIDw8LSBQLnBhdHRlcm4oY3VycmVudC50aW1lKSAgI3Nob3VsZCBiZSBhIGdsb2JhbCB2YXJpYWJsZSwgaGVuY2UgPDwtLCBmb3IgdGhlIEdXLnRyYW5zIG1vZGVsDQogICAgc29sdmUuc3RlcHMoR1cudHJhbnMpDQogICAgIyAgcGxvdChHVy50cmFucyxmbHV4cGxvdCA9IFQpDQogICAgI3NhdmUgaW50ZXJtZWRpYXRlIGRhdGENCiAgICB3YiA9IGRhdGFmcmFtZS5iYWxhbmNlKEdXLnRyYW5zKQ0KICAgIEdXLlEudHJhbnMgPSByYmluZChHVy5RLnRyYW5zLCBjKGN1cnJlbnQudGltZSx3YlsyLDNdLHdiWzMsMl0sd2JbMywzXSx3Yls0LDJdLHdiWzUsM10pKQ0KICAgIEdXLkgudHJhbnMgPSByYmluZChHVy5ILnRyYW5zLCBkYXRhZnJhbWUuc3RhdGVzKEdXLnRyYW5zKVssMl0pDQogICAgI3NhdmUgaW50ZXJtZWRpYXRlIGRhdGEgIA0KICAgIG9sZC5zdGF0ZSA8PC0gc3RhdGUuZnVuKEdXLnRyYW5zKQ0KICB9DQogICNicm93c2VyKCkNCiAgIyBTdG9yaW5nIGRhdGEgDQogIEdXLlEudHJhbnMgPSBkYXRhLmZyYW1lKEdXLlEudHJhbnMpDQogIGNvbG5hbWVzKEdXLlEudHJhbnMpID0gYygidGltZSIsICJzdXJmYWNlX3J1bm9mZiIsInN0b3JhZ2VfaW4iLCJzdG9yYWdlX291dCIsInByZWNpcCIsImJvdW5kYXJ5IikNCiAgR1cuSC50cmFucyA9IGRhdGEuZnJhbWUoR1cuSC50cmFucykNCiAgDQogICMgU2NhbGluZyB0aGUgZ3JvdW5kd2F0ZXIgZmx1eGVzIHRvIGxhdGVyYWwgaW5mbHV4ZXMgZm9yIHRoZSBvcGVuIHdhdGVyIG1vZGVsDQogIFEuZHJhaW5hZ2UubTMuZCA9IEdXLlEudHJhbnMkYm91bmRhcnkgKiBtMi5kYXkudG8ubTMuZGF5DQogIFEuZHJhaW5hZ2UubTMucyA9IFEuZHJhaW5hZ2UubTMuZC9kYXkyc2VjDQogIFEuZHJhaW5hZ2UubTIucyA9IFEuZHJhaW5hZ2UubTMucy9IUi5sZW5ndGgNCiAgDQogIFEucnVub2ZmLm0zLmQgPSBHVy5RLnRyYW5zJHN1cmZhY2VfcnVub2ZmICogbTIuZGF5LnRvLm0zLmRheQ0KICBRLnJ1bm9mZi5tMy5zID0gUS5ydW5vZmYubTMuZC9kYXkyc2VjDQogIFEucnVub2ZmLm0yLnMgPSBRLnJ1bm9mZi5tMy5zL0hSLmxlbmd0aA0KICANCiAgDQogICMjIHRoZSBvcGVuIHdhdGVyIG1vZGVsIGxvb3ANCiAgDQogIA0KICAjZGF0YSBjb250YWluZXJzIGZvciByZXN1bHRzDQogIEhSLlEudHJhbnMgPSBjKCkNCiAgSFIuaC50cmFucyA9IGMoKQ0KICBIUi5RX3Vwc3RyZWFtID0gYygpDQogIEhSLlFfZG93bnN0cmVhbSA9IGMoKQ0KICAjZGF0YSBjb250YWluZXIgZm9yIHJlc3VsdHMNCiAgDQogICN0aW1lIHN0ZXBzIGZvciB0aGUgbG9vcA0KICBjdXJyZW50LnRpbWUgPSBzdGFydC50aW1lDQogICN0aW1lIHN0ZXAgZm9yIHJldHJpZXZpbmcgZGF0YSBmcm9tIGRyYWluYWdlIGFuZCBzdXJmYWNlIHRpbWUgc2VyaWVzIG9mIHRoZSBncm91bmR3YXRlciBtb2RlbA0KICB0aW1lLnN0ZXAgPXN0YXJ0LnRpbWUNCiAgd2hpbGUoY3VycmVudC50aW1lIDwgZW5kLnRpbWUpDQogICAgDQogIHsNCiAgICBjdXJyZW50LnRpbWUgPSBjdXJyZW50LnRpbWUgKyBkZWx0LnQNCiAgICB0aW1lLnN0ZXAgPSB0aW1lLnN0ZXAgKyAxDQogICAgZHJhaW5hZ2UgPDwtIFEuZHJhaW5hZ2UubTIuc1t0aW1lLnN0ZXBdICAjZ2xvYmFsIHZhcmlhYmxlIGZvciBnbG9iYWwgSFIuYmFja3dhdGVybW9kZWwNCiAgICBydW5vZmYgPDwtIFEucnVub2ZmLm0yLnNbdGltZS5zdGVwXSAgI2dsb2JhbCB2YXJpYWJsZSBmb3IgZ2xvYmFsIEhSLmJhY2t3YXRlcm1vZGVsDQogICAgDQogICAgc29sdmUuc3RlcHMoSFIuYmFja3dhdGVybW9kZWwpDQogICAgIyNzYXZpbmcgaW50ZXJtZWRpYXRlIHJlc3VsdHMNCiAgICB3YiA9IGRhdGFmcmFtZS5iYWxhbmNlKEhSLmJhY2t3YXRlcm1vZGVsKQ0KICAgIEhSLlEudHJhbnMgPSByYmluZChIUi5RLnRyYW5zLCBjKGN1cnJlbnQudGltZSx3Yls0LDJdLHdiWzMsMl0sd2JbMiwyXSx3Yls0LDNdKSkNCiAgICBIUi5oLnRyYW5zID0gcmJpbmQoSFIuaC50cmFucywgZGF0YWZyYW1lLnN0YXRlcyhIUi5iYWNrd2F0ZXJtb2RlbClbLDJdKQ0KICAgICMjc2F2aW5nIGludGVybWVkaWF0ZSByZXN1bHRzDQogIH0NCiAgI2Jyb3dzZXIoKQ0KICBIUi5RLnRyYW5zID0gZGF0YS5mcmFtZShIUi5RLnRyYW5zKQ0KICBjb2xuYW1lcyhIUi5RLnRyYW5zKSA9IGMoInRpbWUiLCJib3VuZGFyeV91cHN0cmVhbSIsInJ1bm9mZiIsImRyYWluYWdlIiwiYm91bmRhcnlfZG93bnN0cmVhbSIpDQogIEhSLmgudHJhbnMgPSBkYXRhLmZyYW1lKEhSLmgudHJhbnMpDQogICNyZXR1cm5pbmcgdGhlIG5ldyBkYXRhLmZyYW1lcyB0byB0aGUgZ2xvYmFsIGVudmlyb25tZW50IGZvciBmdXJ0aGVyIGFuYWx5c2lzLg0KICBHVy5RLnRyYW5zIDw8LSBHVy5RLnRyYW5zDQogIEdXLkgudHJhbnMgPDwtIEdXLkgudHJhbnMNCiAgSFIuUS50cmFucyA8PC0gSFIuUS50cmFucw0KICBIUi5oLnRyYW5zIDw8LSBIUi5oLnRyYW5zDQp9DQpgYGANCg0KDQojIyMgTG9jYWwgc2Vuc2l0aXZpdGllcw0KDQpFYWNoIGxvY2FsIHNlbnNpdGl2aXR5IGNhbiBub3cgYmUgZGV0ZXJtaW5lZCB1c2luZyBhIHNlcXVlbmNlIG9mOiAgDQoNCiogIGFkZGluZyBgZXBzYCB0byB0aGUgY3VycmVudCBwYXJhbWV0ZXIgJFBfaSQNCiogIHJ1bm5pbmcgdGhlIGBTZW5zaXRpdml0eS5sb29wKClgIA0KKiAgY2FsY3VsYXRpbmcgJFxmcmFje1xwYXJ0aWFsIFx0ZXh0e01SRVNVTFQoKX19e1xwYXJ0aWFsIFBfaX0kDQoqICBzdWJ0cmFjdGluZyBgZXBzYCBmcm9tIHRoZSBjdXJyZW50IHBhcmFtZXRlci4gIA0KDQo8ZGl2IGNsYXNzPSJxdWVzdGlvbiI+DQpTZXQgdXAgdGhlIHNlbnNpdGl2aXR5IHNlcXVlbmNlLCBzZWUgYWJvdmUsIHRvIGRldGVybWluZSB0aGUgbG9jYWwgc2Vuc2l0aXZpdGllcyBmb3IgdGhlIGNob3NlbiBwYXJhbWV0ZXJzLiAgDQoNCioqVElQKio6IHlvdSBjYW4gdXNlIGBlcHNgIGJlaW5nIGFuIG9mZnNldCBzbywgJFBfaSA9IFBfaSArIGVwcyQgb3IgdXNlIGl0IGFzIGEgZnJhY3Rpb246ICRQX2kgPSBQX2kqKDEgKyBlcHMpJA0KDQpgYGB7ciBldmFsID0gVFJVRX0NCiMgT3V0cHV0IG9mIGludGVyZXN0Og0KIyAgIDEuIE1heGltdW0gZGlzY2hhcmdlIGF0IHRoZSB3ZWlyIChNUkVTVUxUMSkNCiMgICAyLiBNYXhpbXVtIGhlYWQgb2YgZ3JvdW5kd2F0ZXIgKE1SRVNVTFQyKQ0KIyAgIDMuIE1heGltdW0gd2F0ZXIgaGVpZ2h0IGF0IEhvb2dlIFJhYW0gKE1SRVNVTFQzKQ0KIyAgIDQuIERyYWluYWdlIG9mIHRoZSBncm91bmR3YXRlciAoTUVSU1VMVDQpDQojICAgNS4gTGFnIG9mIG1heGltdW0gcHJlY2lwaXRhdGlvbiBhbmQgdGhlIG1heGltdW0gaGVhZCBvZiBncm91bmR3YXRlciBvciB3aXRoIG1heCBydW5vZmYgKE1SRVNVTFQ1KQ0KDQojIElucHV0DQojIGdyb3VuZHdhdGVyIG1vZGVsOg0KIyAxLiBUcmFuc21pc3Npdml0eSBvZiB0aGUgc3Vic29pbCBHVy5rRA0KIyAyLiBFbnRyYW5jZSByZXNpc3RhbmNlIG9mIHRoZSBkaXRjaCBDX2RpdGNoDQojIDMuIEF2ZXJhZ2UgZHJhaW4gbGV2ZWwgb2YgdGhlIGFyZWEgSF9kcmFpbmFnZQ0KIyA0LiBWZXJ0aWNhbCByZXNpc3RhbmNlIHRvcCBsYXllciBzb2lsIENfc3VyZmFjZQ0KIyA1LiBBdmVyYWdlIHN1cmZhY2UgbGV2ZWwgZHJhaW5hZ2Ugc3lzdGVtIEhfc3VyZmFjZQ0KIyA2LiBTdG9yYWdlIGNvZWZmaWNpZW50OyBHVy5TDQojIA0KIyBvcGVuIHdhdGVyIG1vZGVsOg0KIyAxLiB2YWx1ZSB3ZWlyIGNvbnN0YW50IChjdXJyZW50bHkgMS44MykNCiMgMi4gV2VpciBjcmVzdCBoZWlnaHQgSFIud2Vpci5jcmVzdA0KIyAzLiBXZWlyIHdpZHRoIEhSLndlaXIud2lkdGgNCiMgNC4gTWFubmluZyBjb2VmZmljaWVudCBIUi5uDQojIDUuIFJpdmVyIHdpZHRoIEhSLmINCiMgNi4gU2lkZSBzbG9wZXMgSFIubQ0KDQpuYW1lcyA9IG5hbWVzKGJhc2UpDQoNCmZvcihpIGluICgxOmxlbmd0aChiYXNlKSkpDQp7DQogIGJhc2UuY3VycmVudCA9IGFzLm51bWVyaWMoYmFzZVtpXSkgI2Jhc2UgdmFsdWUgb2YgcGFyYW1ldGVyW2ldDQogIHNjYWxlLmN1cnJlbnQgPSBhcy5udW1lcmljKHNjYWxlW2ldKSAjc2NhbGUgb2YgdmFyaWF0aW9uIGluIHRlcm1zIG9mIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBwYXJhbWV0ZXJbaV0NCiAgZXBzID0gMS8xMDAqc2NhbGUuY3VycmVudCAjd2UgdGFrZSBlcHNpbG9uIGFzIDElIG9mIHRoZSBzY2FsZSBvZiB2YXJpYXRpb24gKHN0YW5kYXJkIGRldmlhdGlvbikNCiAgDQogIG5hbWUgPSBuYW1lc1tpXSAjdmFyaWFibGVzIHRoYXQgd2Ugd2FudCB0byBjaGFuZ2UNCiAgDQogIGFzc2lnbihuYW1lLCBiYXNlLmN1cnJlbnQrZXBzLCBlbnZpciA9IC5HbG9iYWxFbnYpICNhc3NpZ25pbmcgbmFtZSB0byBiYXNlK2Vwcw0KICBTZW5zaXRpdml0eS5sb29wKCkgI3J1bm5pbmcgdGhlIGNvdXBsaW5nIG1vZGVsDQogIGFzc2lnbihuYW1lLCBiYXNlLmN1cnJlbnQsIGVudmlyID0gLkdsb2JhbEVudikgI2NoYW5naW5nIHZhcmlhYmxlcyBiYWNrIHRvIGJhc2UNCiAgI3ByaW50KGdldChuYW1lLCBlbnZpciA9IC5HbG9iYWxFbnYpKQ0KICBwcmludChNUkVTVUxUKCkpDQoNCn0NCmBgYA0KPC9kaXY+DQoNCg0KDQoNCiMjIyBUb3RhbCBhbmQgcGFydGlhbCB2YXJpYW5jZXMNCg0KUmVjYWxsIHRoZSBwcmV2aW91cyBMb2NhbCBTZW5zaXRpdml0eSBBc3NpZ25tZW50IHdoZXJlIHlvdSBjYWxjdWxhdGVkIHRoZTogIA0KDQoqICB2YXJpYW5jZXMgZm9yIGVhY2ggcGFyYW1ldGVyIGJhc2VkIG9uIGl0cyBzY2FsZSBvZiB2YXJpYW5jZSBhbmQgdGhlIGxvY2FsIHNlbnNpdGl2aXR5IG9mIHRoYXQgcGFyYW1ldGVyIHcuci50LiBgTVJFU1VMVCgpYA0KKiAgY2FsY3VsYXRlIHRoZSBzdW0gb2YgdGhlc2UgdmFyaWFuY2VzDQoqICBjYWxjdWxhdGUgdGhlIHJlbGF0aXZlIGNvbnRyaWJ1dGlvbiBvZiBlYWNoIHBhcmFtZXRlciB0byB0aGUgdG90YWwgdmFyaWFuY2UNCiogIHBsb3QgYSBwaWUgY2hhcnQgdG8gdmlzdWFsaXplIHRoZSBjb250cmlidXRpb25zIHRvIHRoZSBkZXJpdmVkIHVuY2VydGFpbnR5IA0KKiAgYSB0YWJsZSBvZiBmcmFjdGlvbnMsIGBrbml0cjo6a2FibGUoKWAgaXMgYWxyZWFkeSBpbXBsZW1lbnRlZCB0byBpbnNwZWN0IHRoZSBwcm9jZW50dWFsIHNlbnNpdGl2aXRpZXMNCg0KPGRpdiBjbGFzcz0icXVlc3Rpb24iPg0KRGV0ZXJtaW5lIHRoZSBkZXJpdmVkIHVuY2VydGFpbnR5IGJhc2VkIG9uIHRoZSBhZm9yZW1lbnRpb25lZCBsaXN0DQoNCmBgYHtyIGV2YWwgPSBGQUxTRX0NCg0KI2EgdGFibGUgZm9yIHNvbWUgcmVzdWx0cyAicmVsdmFyTSIgY29udGFpbnMgdGhlIHJlbGF0aXZlIHZhcmlhbmNlcyBvZiBNUkVTVUxUDQprbml0cjo6a2FibGUoYXMuZGF0YS5mcmFtZShyZWx2YXJNKSoxMDAsIGNhcHRpb24gPSAicGVyY2VudGFnZSBsb2NhbCBzZW5zaXRpdml0aWVzIixhbGlnbj0iYyIpDQoNCmBgYA0KDQo8L2Rpdj4NCg0KMS4wMDk1MjI1DQoNCg==